sofa-rpc 学习总结
如下是client调用流程图:
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) {
}
}
}
- 结合图与样例代码,根据config配置信息生成对应的HelloSyncService的proxy对象。
- refer方法的核心实现是DefaultConsumerBootstrap.refer();
- 代理对象的的代理类是DefaultClientProxyInvoker.invoke(),完成对remote服务选择,调用
- cluster是调用请求的具体组织类,它包括调用(路由、地址管理器、连接管理器、负载均衡器,过滤器)。
- cluster.sendMsg()是最终的网络请求类。
代码具体学习
[外链图片转存失败(img-aRrpAj1H-1565165440786)(./sofa-rpc-all.png)]
- 通过目录结构可以了解大致结构模块
- 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());
}
- ExtensionLoaderFactory就是ExtensionLoader的工厂构造器,并有一个ConcurrentMap<Class, ExtensionLoader> LOADER_MAP的cache。
- ExtensionLoader是具体加载器,用于从相应接口的 SPI 配置文件中读取配置内容并且将每一行解析成一个 ExtensionClass(每一个 ExtensionClass 对应一个实现,SPI 配置文件中的每一行配置一个实现类),之后存储 <alias, ExtensionClass> 配置对到 Map<String, ExtensionClass> 容器中
- 具体参考 https://www.jianshu.com/p/4acdc72b38a9
- rpc的LoadBalancer,Filter,proxy实现,等很多机制都是spi配置化。
rpc客户初始过程
- consumerConfig表示本次client调用基础属性,RegistryConfig表达采用什么register center信息。
- 可以看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();
}
- refer()是获取具体代理类instance,看如上代码,Bootstraps.from(this)是根据自己协议spi机制加载不同consumerBootstrap实现类。
- consumerBootstrap看下spi配置,就明白了就是rpc支持bolt,dubbo,rest各种协议实现。
- 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是过滤spi获取cluster配置FailoverCluster
- @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会初始directUrl,mesh,Registry三个Router
- @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为proxy instance调用方法
- @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) {
- @10 select()方法会根据loadbalaner策略选择具体providerInfo生产者信息。
- @11 通过如下RpcReferenceContextFilter,ConsumerExceptionFilter ,ConsumerTracerFilter ,最终调用到sendMsg()。参考堆栈信息
- 后面就是基于netty网络协议封装
netty网络层封装
- 对于netty网络层封装都在bolt-1.4.6.jar里
- RpcServer是对NioServerSocketChannel的封装,doInit()是netty模板代码