sofa-rpc 学习总结

sofa-rpc 学习总结

如下是client调用流程图:


broker


client调用样例代码:


 @Test
    public void testHelloSyncService() {

        // 指定注册中心
        RegistryConfig registryConfig = new RegistryConfig()
                .setProtocol("zookeeper")
                .setAddress("127.0.0.1:2181");


        ConsumerConfig<HelloSyncService> consumerConfig = new ConsumerConfig<HelloSyncService>()
                .setInterfaceId(HelloSyncService.class.getName()) // 指定接口
                .setProtocol("bolt") // 指定协议
//                .setDirectUrl("bolt://127.0.0.1:12200"); // 指定直连地址
                .setRegistry(registryConfig);
        // 生成代理类
        HelloSyncService helloService = consumerConfig.refer();
        while (true) {
            System.out.println(helloService.saySync("world"));
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
            }
        }
    }


  1. 结合图与样例代码,根据config配置信息生成对应的HelloSyncService的proxy对象。
  2. refer方法的核心实现是DefaultConsumerBootstrap.refer();
  3. 代理对象的的代理类是DefaultClientProxyInvoker.invoke(),完成对remote服务选择,调用
  4. cluster是调用请求的具体组织类,它包括调用(路由、地址管理器、连接管理器、负载均衡器,过滤器)。
  5. cluster.sendMsg()是最终的网络请求类。
代码具体学习

[外链图片转存失败(img-aRrpAj1H-1565165440786)(./sofa-rpc-all.png)]


在这里插入图片描述

  1. 通过目录结构可以了解大致结构模块
  2. sofa采用spi的关闭修改开放扩展的方式组织各个模块。请查看META-INF/services/sofa-rpc/
sofa的spi机制
@Test
    public void testLoad(){
        ExtensionLoader<LoadBalancer> loader = ExtensionLoaderFactory.getExtensionLoader(LoadBalancer.class);
        LoadBalancer myLoadBalancer = loader.getExtension("random");
        System.out.println(myLoadBalancer.getClass().getName());
    }

  1. ExtensionLoaderFactory就是ExtensionLoader的工厂构造器,并有一个ConcurrentMap<Class, ExtensionLoader> LOADER_MAP的cache。
  2. ExtensionLoader是具体加载器,用于从相应接口的 SPI 配置文件中读取配置内容并且将每一行解析成一个 ExtensionClass(每一个 ExtensionClass 对应一个实现,SPI 配置文件中的每一行配置一个实现类),之后存储 <alias, ExtensionClass> 配置对到 Map<String, ExtensionClass> 容器中
  3. 具体参考 https://www.jianshu.com/p/4acdc72b38a9
  4. rpc的LoadBalancer,Filter,proxy实现,等很多机制都是spi配置化。
rpc客户初始过程
  1. consumerConfig表示本次client调用基础属性,RegistryConfig表达采用什么register center信息。
  2. 可以看consumerConfig很多属性来源RpcConfigs类,rpc很基础属性配置由RpcConfigs读取不同配置文件,包括(rpc-config-default.json;sofa-rpc/rpc-config.json;META-INF/sofa-rpc/rpc-config.json)

 public T refer() {
        if (consumerBootstrap == null) {
            consumerBootstrap = Bootstraps.from(this);
        }
        return consumerBootstrap.refer();
    }
    
  1. refer()是获取具体代理类instance,看如上代码,Bootstraps.from(this)是根据自己协议spi机制加载不同consumerBootstrap实现类。
  2. consumerBootstrap看下spi配置,就明白了就是rpc支持bolt,dubbo,rest各种协议实现。
  3. consumerBootstrap.refer()是如下代码
    // build cluster
    cluster = ClusterFactory.getCluster(this);   @1
    // build listeners
    consumerConfig.setConfigListener(buildConfigListener(this));
    consumerConfig.setProviderInfoListener(buildProviderInfoListener(this));
    // init cluster
    cluster.init();   @4
    // 构造Invoker对象(执行链)
    proxyInvoker = buildClientProxyInvoker(this);
    // 创建代理类
    proxyIns = (T) ProxyFactory.buildProxy(consumerConfig.getProxy(), consumerConfig.getProxyClass(),
        proxyInvoker);

  1. @1是过滤spi获取cluster配置FailoverCluster
  2. @4里面的初始化,代码如下,结果上面调用流程图可以明白,核心routerChain,loadbalancer,filter等初始化。
public synchronized void init() {
        if (initialized) { // 已初始化
            return;
        }
        // 构造Router链
        routerChain = RouterChain.buildConsumerChain(consumerBootstrap);   @1
        // 负载均衡策略 考虑是否可动态替换?
        loadBalancer = LoadBalancerFactory.getLoadBalancer(consumerBootst@1rap);  @2
        // 地址管理器
        addressHolder = AddressHolderFactory.getAddressHolder(consumerBootstrap);
        // 连接管理器
        connectionHolder = ConnectionHolderFactory.getConnectionHolder(consumerBootstrap);
        // 构造Filter链,最底层是调用过滤器
        this.filterChain = FilterChain.buildConsumerChain(this.consumerConfig,
            new ConsumerInvoker(consumerBootstrap));

        if (consumerConfig.isLazy()) { // 延迟连接
            if (LOGGER.isInfoEnabled(consumerConfig.getAppName())) {
                LOGGER.infoWithApp(consumerConfig.getAppName(), "Connection will be initialized when first invoke.");
            }
        }

        // 启动重连线程
        connectionHolder.init();
        try {
            // 得到服务端列表
            List<ProviderGroup> all = consumerBootstrap.subscribe();    @7
            if (CommonUtils.isNotEmpty(all)) {
                // 初始化服务端连接(建立长连接)
                updateAllProviders(all);  @8
            }
        } catch (SofaRpcRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SofaRpcRuntimeException("Init provider's transport error!", e);
        }

        // 启动成功
        initialized = true;

        // 如果check=true表示强依赖
        if (consumerConfig.isCheck() && !isAvailable()) {
            throw new SofaRpcRuntimeException("The consumer is depend on alive provider " +
                "and there is no alive provider, you can ignore it " +
                "by ConsumerConfig.setCheck(boolean) (default is false)");
        }
    }
    
  1. @1会初始directUrl,mesh,Registry三个Router
  2. @7会初始化RegistryRouter里的Registry器,可以根据如下堆栈信息查看,subscribeFromRegistries根据配置RegistryConfig信息来加载并初始化ZookeeperRegister。
init:220, ZookeeperRegistry (com.alipay.sofa.rpc.registry.zk)
subscribeFromRegistries:328, DefaultConsumerBootstrap (com.alipay.sofa.rpc.bootstrap)
subscribe:261, DefaultConsumerBootstrap (com.alipay.sofa.rpc.bootstrap)
init:144, AbstractCluster (com.alipay.sofa.rpc.client)
refer:152, DefaultConsumerBootstrap (com.alipay.sofa.rpc.bootstrap)
refer:926, ConsumerConfig (com.alipay.sofa.rpc.config)
testHelloSyncService:26, HelloSyncServiceTest (com.bank.app.user.service)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
runReflectiveCall:50, FrameworkMethod$1 (org.junit.runners.model)
run:12, ReflectiveCallable (org.junit.internal.runners.model)
invokeExplosively:47, FrameworkMethod (org.junit.runners.model)
evaluate:17, InvokeMethod (org.junit.internal.runners.statements)
runLeaf:325, ParentRunner (org.junit.runners)
runChild:78, BlockJUnit4ClassRunner (org.junit.runners)
runChild:57, BlockJUnit4ClassRunner (org.junit.runners)
run:290, ParentRunner$3 (org.junit.runners)
schedule:71, ParentRunner$1 (org.junit.runners)
runChildren:288, ParentRunner (org.junit.runners)
access$000:58, ParentRunner (org.junit.runners)
evaluate:268, ParentRunner$2 (org.junit.runners)
run:363, ParentRunner (org.junit.runners)
run:137, JUnitCore (org.junit.runner)
startRunnerWithArgs:68, JUnit4IdeaTestRunner (com.intellij.junit4)
startRunnerWithArgs:47, IdeaTestRunner$Repeater (com.intellij.rt.execution.junit)
prepareStreamsAndStart:242, JUnitStarter (com.intellij.rt.execution.junit)
main:70, JUnitStarter (com.intellij.rt.execution.junit)

请求调用流程

doSendMsg:503, AbstractCluster (com.alipay.sofa.rpc.client)       @7
sendMsg:485, AbstractCluster (com.alipay.sofa.rpc.client)         @6
invoke:60, ConsumerInvoker (com.alipay.sofa.rpc.filter)
invoke:66, ConsumerTracerFilter (com.alipay.sofa.rpc.filter.sofatracer)
invoke:96, FilterInvoker (com.alipay.sofa.rpc.filter)
invoke:80, RpcReferenceContextFilter (com.alipay.sofa.rpc.filter)
invoke:96, FilterInvoker (com.alipay.sofa.rpc.filter)
invoke:37, ConsumerExceptionFilter (com.alipay.sofa.rpc.filter)
invoke:96, FilterInvoker (com.alipay.sofa.rpc.filter)
invoke:262, FilterChain (com.alipay.sofa.rpc.filter)
filterChain:478, AbstractCluster (com.alipay.sofa.rpc.client)
doInvoke:66, FailoverCluster (com.alipay.sofa.rpc.client)    @2
invoke:285, AbstractCluster (com.alipay.sofa.rpc.client)
invoke:83, ClientProxyInvoker (com.alipay.sofa.rpc.client)
saySync:-1, HelloSyncService_proxy_0 (com.xw.bank.user.service)   @1
testHelloSyncService:28, HelloSyncServiceTest (com.bank.app.user.service)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
runReflectiveCall:50, FrameworkMethod$1 (org.junit.runners.model)
run:12, ReflectiveCallable (org.junit.internal.runners.model)
invokeExplosively:47, FrameworkMethod (org.junit.runners.model)
evaluate:17, InvokeMethod (org.junit.internal.runners.statements)
runLeaf:325, ParentRunner (org.junit.runners)
runChild:78, BlockJUnit4ClassRunner (org.junit.runners)
runChild:57, BlockJUnit4ClassRunner (org.junit.runners)
run:290, ParentRunner$3 (org.junit.runners)
schedule:71, ParentRunner$1 (org.junit.runners)
runChildren:288, ParentRunner (org.junit.runners)
access$000:58, ParentRunner (org.junit.runners)
evaluate:268, ParentRunner$2 (org.junit.runners)
run:363, ParentRunner (org.junit.runners)
run:137, JUnitCore (org.junit.runner)
startRunnerWithArgs:68, JUnit4IdeaTestRunner (com.intellij.junit4)
startRunnerWithArgs:47, IdeaTestRunner$Repeater (com.intellij.rt.execution.junit)
prepareStreamsAndStart:242, JUnitStarter (com.intellij.rt.execution.junit)
main:70, JUnitStarter (com.intellij.rt.execution.junit)

  1. 根据上面堆栈信息可以大致看到调用流程。
  2. @1为proxy instance调用方法
  3. @2是真正调用逻辑的开始,看如下代码

public SofaResponse doInvoke(SofaRequest request) throws SofaRpcException {
        String methodName = request.getMethodName();
        int retries = consumerConfig.getMethodRetries(methodName);
        int time = 0;
        SofaRpcException throwable = null;// 异常日志
        List<ProviderInfo> invokedProviderInfos = new ArrayList<ProviderInfo>(retries + 1);
        do {
            ProviderInfo providerInfo = select(request, invokedProviderInfos);   @10
            try {
                SofaResponse response = filterChain(providerInfo, request);      @11  
                if (response != null) {
                    if (throwable != null) {
                        if (LOGGER.isWarnEnabled(consumerConfig.getAppName())) {
                            LOGGER.warnWithApp(consumerConfig.getAppName(),
                                LogCodes.getLog(LogCodes.WARN_SUCCESS_BY_RETRY,
                                    throwable.getClass() + ":" + throwable.getMessage(),
                                    invokedProviderInfos));
                        }
                    }
                    return response;
                } else {
                    throwable = new SofaRpcException(RpcErrorType.CLIENT_UNDECLARED_ERROR,
                        "Failed to call " + request.getInterfaceName() + "." + methodName
                            + " on remote server " + providerInfo + ", return null");
                }
            } catch (SofaRpcException e) { 

  1. @10 select()方法会根据loadbalaner策略选择具体providerInfo生产者信息。
  2. @11 通过如下RpcReferenceContextFilter,ConsumerExceptionFilter ,ConsumerTracerFilter ,最终调用到sendMsg()。参考堆栈信息
  3. 后面就是基于netty网络协议封装
netty网络层封装
  1. 对于netty网络层封装都在bolt-1.4.6.jar里
  2. RpcServer是对NioServerSocketChannel的封装,doInit()是netty模板代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值