dubbo-io学习

dubbo支持netty、mina、grizzly等网络框架,这也使得它的io抽象的非常复杂,什么exchange、transporter,让人一头雾水。从本质来看,也应该是抽象出dubbo自己的读、写、连接等IO事件,然后将各个网络框架的事件转发到dubbo的io事件上去。我们不去care这些抽象的细节,只关注dubbo是如何实现常见的几个网络io问题

连接管理

dubbo使用ConcurrentHashMap来保存连接,key是ip:port, value是dubbo的抽象代表一个连接的channel。
ConcurrentHashMap使用容器分离减少锁的粒度,通过cas空旋代替悲观锁,同时使用volatile做到读不加任何锁。连接创建的时候,put一个连接到map的性能应该是非常高

考虑服务端保存这些连接主要是想对这些连接做空闲连接管理。也即需要遍历下map中所有的连接,然后传给空闲连接task

public Collection<Channel> getChannels() {
    Collection<Channel> chs = new HashSet<Channel>();
    for (Channel channel : this.channels.values()) {
        if (channel.isConnected()) {
            chs.add(channel);
        } else {
            channels.remove(NetUtils.toAddressString(channel.getRemoteAddress()));
        }
     }
     return chs;
 }

上面的代码其实是对map做了一次copy,那这里直接使用CopyOnWriteArrayList是不是会更好呢。因为rpc这种内部框架客户端连接跟连接数一般都是十分稳定的,并且一个服务器顶多也就几千的连接

空闲连接管理

dubbo服务端使用定时任务进行空闲连接管理,在服务器初始化的时候,会启动一个HashedWheelTimer进行管理。dubbo没有使用netty的idle事件,主要原因可能是因为dubbo需要还支持mina、grizzly等这种网络框架,所以统一使用了定时任务来管理

心跳

心跳是客户端主动发起的,跟空闲连接管理一样,同样也是使用了HashedWheelTimer`的一个定时任务。

重连

通常rpc不需要断线重连,个人觉得原因是:

  1. 内部网络稳定,因网络问题断线概率低
  2. 可以在rpc调用的时候,再去获取一个连接,就算有断线重连这步还是无法避免

但是dubbo还是在客户端提供了断线重连的的定时任务ReconnectTimerTask

总结

简单总结下,dubbo为了兼容各个网络框架,使用各种定时任务进行连接管理。从常用io框架设计角度来看,把空闲、心跳、跟重连抽象成一个事件可能比定时任务更容易理解

猜你喜欢

转载自blog.csdn.net/weixin_34029949/article/details/86941539