Skip to content

【样例工程】一个dubbo sidecar的设计思路

Notifications You must be signed in to change notification settings

chpengzh/dubbo-mesh-java

Repository files navigation

Dubbo 透明协议代理

问题背景

由于dubbo的协议头定义对service-mesh不太友好,所以dubbo一直以来都没有比较好的mesh化落地方案;

由于我在的公司里面java体系主要也是使用dubbo,因此决定考察一种无痛升级方式,在定制sidecar-agent层与客户端的协议的同时,兼容提供者序列化协议;

这样有一个好处是,升级期间提供者不需要进行改造,而服务消费者改动量也只是一个编码协议与地址变更;

整体协议力促恒如下:

Dubbo Consumer Applicaiton                    transport layer                        Dubbo Mesh Proxy Applicaiton                                Dubbo Mesh Proxy Applicaiton                Dubbo Provider Applicaiton        
                                                                                         NettyProxyServer                                         NettyProxyClient

dubboProxyClientCdec#encodeRequest   --->   PayloadRequest                    --->   dubboProxyServerCodec#decodeRequest
                                             header:                                             
                                                 interface                                        |
                                                 version                                          |
                                                 group                                            |- PayloadRpcInvocation      --->       dubboProxyServerCodec#encodeRequest     --->              -----
                                                 method                                                      |                                                                                        |
                                                 method_parameters_desc                                      |                                                                                        |
                                                 attachments                                                 |                                                                                        |
                                             body:                                                           |                                                                 
                                                 requestPayload                                              |----- InvocationChain & AsyncFilter                                            Business Threadpool
                                                                                                             |
                                                                                                             |                                                                                        |
                                                                                                             |                                                                                        |
                                                                                                             |                                                                                        |
                                                                                                 |- PayloadRpcResult          <---       dubboProxyServerCodec#decodeResponse    <---               -----
                                                                                                 |
                                             PayloadResponse                                     |
                                             data:
dubboProxyClientCdec#decodeResponse   <---        responsePayload                <---  dubboProxyServerCodec#encodeResponse

        
|----------------------------------|                                                             |---------------------------------------------------------|
          
         Dubbo Mesh SDK                                                                                            Dubbo Mesh Agent Server

动动你的小手

  1. 本地启动zk作为服务注册发现中心,地址 zookeeper://127.0.0.1:2181

  2. 启动本地提供者样例, 主方法在example-provider中,启动类com.github.example.ServerMain

public class ServerMain {

    public static void main(String[] args) throws InterruptedException {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("sidecar-dubbo");

        ProviderConfig provider = new ProviderConfig();
        provider.setVersion("1.0.0");
        provider.setGroup("some_group");

        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setPort(9000);

        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("zookeeper://127.0.0.1:2181");

        ServiceConfig<TestApi> service = new ServiceConfig<>();
        service.setInterface(TestApi.class);
        service.setRef((name, order) -> "hello, " + name.getName());
        service.setApplication(application);
        service.setRegistry(registry);
        service.setProvider(provider);
        service.setProtocol(protocol);
        service.export();

        new CountDownLatch(1).await();
    }
}
  1. 启动 sidecar-dubbo-server,主方法在org.apache.dubbo.DubboMeshLauncher

  2. 启动本地消费者 example-provider,主方法在 com.github.example.ClientMain,应用能正常返回.

注意与普通消费相比,唯一的区别即是变更了直连url地址

public class ClientMain {

    public static void main(String[] args) throws InterruptedException {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("sidecar-dubbo");

        ConsumerConfig consumer = new ConsumerConfig();
        consumer.setVersion("1.0.0");
        consumer.setGroup("some_group");
        consumer.setTimeout(1000000);

        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("zookeeper://127.0.0.1:2181");

        ReferenceConfig<TestApi> reference = new ReferenceConfig<>();
        reference.setInterface(TestApi.class);
        reference.setApplication(application);
        reference.setRegistry(registry);
        reference.setConsumer(consumer);
        reference.setUrl("dubbo-proxy-client://127.0.0.1:8999");
        TestApi testApi = reference.get();

        RpcContext.getContext().setAttachment("abcde", "xxxx");
        System.err.println(JSON.toJSON(testApi.sayHello(new TestModel("chpengzh"), 12)));
    }
}
  1. 值得注意的是,由于我们的sidecar是使用的codec扩展,因此可以按照dubbo的纯异步模型调参,也可以使用filter扩展
public class DubboMeshLauncher {

    public static void main(String[] args) throws IOException {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("sidecar-dubbo-srever");

        //
        // Dubbo Protocol 定义:
        // 1.使用协议名称 dubbo-proxy-server
        // 2.因为是纯异步实现,所以只需要核心数相等的线程即可,减少cpu调度消耗
        // 3.相应的要调整等待队列大小,防止因为并发执行耗时误差调至的拒绝策略
        //
        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setPort(8999);
        protocol.setName("dubbo-proxy-server");
        protocol.setDispatcher("direct");

        //
        // Dubbo Registry
        // 1.服务注册发现可以继续使用zk或者别的注册发现中心
        // 2.亦或是灰度期间使用双注册模式
        //
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("zookeeper://127.0.0.1:2181");
        registry.setRegister(false);

        //
        // Dubbo Consumer 定义
        // 1.使用泛化调用声明是为了保障proxy在没有接口依赖的情况下不进行运行时校验
        // 2.使用异步配置
        // 2.使用全局的注册发现中心
        //
        ConsumerConfig consumer = new ConsumerConfig();
        consumer.setAsync(true);
        consumer.setRegistry(registry);
        consumer.setApplication(application);

        //
        // Dubbo Reference 定义
        // 1.以下信息个性数据来自于业务应用初始化上报
        // 2.使用的编解码协议是 dubbo-proxy-server
        //
        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
        reference.setInterface("com.github.example.TestApi");
        reference.setVersion("1.0.0");
        reference.setGroup("some_group");
        reference.setTimeout(1000000);
        reference.setProtocol("dubbo-proxy-server");
        reference.setConsumer(consumer);
        reference.setGeneric(true);
        consumer.setCheck(false);
        GenericService outputFacade = reference.get();

        //
        // 代理接口服务
        // 1.所有的应用的出口流量均在这个服务中进行处理
        // 2.可以支持到Filter实现异步逻辑扩展
        //
        ServiceConfig<DubboProxyInputFacade> service = new ServiceConfig<>();
        service.setInterface(DubboProxyInputFacade.class);
        service.setRef((payloads, headers, attachment) -> {
            // 这里是在业务线程池里面进行的
            System.out.println(outputFacade.$invoke("", new String[0], new Object[]{payloads}));
            //noinspection unchecked
            return (CompletableFuture) RpcContext.getContext().getFuture();
        });
        service.setVersion("1.0.0");
        service.setGroup("");
        service.setApplication(application);
        service.setRegistry(registry);
        service.setProtocol(protocol);
        service.export();

        System.in.read();
    }
}

About

【样例工程】一个dubbo sidecar的设计思路

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages