2020-12-26

博客园Logo
首页
新闻
博问
专区
闪存
班级

代码改变世界
搜索
注册
登录
罗西的思考
一手伸向技术,一手伸向生活
博客园 首页 新随笔 联系 订阅 管理 随笔 - 113 文章 - 0 评论 - 14
[从源码学设计]蚂蚁金服SOFARegistry之Data节点变更

[从源码学设计]蚂蚁金服SOFARegistry之Data节点变更
目录
[从源码学设计]蚂蚁金服SOFARegistry之Data节点变更
0x00 摘要
0x02 引子
0x03 业务范畴
3.1 DataServer 数据一致性
3.2 节点变更时的数据同步
0x04 总体逻辑
0x05 DataServerChangeEvent
5.1 消息来源
5.1.1 启动
5.1.1.1 产生消息
5.1.1.2 MetaServerChangeEventHandler
5.1.2 推送
5.1.2.1 推送
5.1.2.2 第一层转换
5.1.2.3 第二层转换
0x06 轮训拉
6.1 Bean
6.2 启动
6.3 ConnectionRefreshTask
0x07 DataServerChangeEventHandler
7.1 总体逻辑
7.2 LocalDataServerChangeEvent
7.3 逻辑图
0x08 总结
0xFF 参考
0x00 摘要
SOFARegistry 是蚂蚁金服开源的一个生产级、高时效、高可用的服务注册中心。

本系列文章重点在于分析设计和架构,即利用多篇文章,从多个角度反推总结 DataServer 或者 SOFARegistry 的实现机制和架构思路,让大家借以学习阿里如何设计。

本文为第十一篇,介绍SOFARegistry如何处理Data节点变化,即处理DataServerChangeEvent消息。

0x02 引子
上文中我们提到,MetaServerChangeEvent也会转化为 DataServerChangeEvent,投放到EventCenter。

这是因为Meta Server的这个推送,也许是在告诉data Server,“hi,目前data server也有变动”。所以本期我们介绍如何处理DataServerChangeEvent,此处需要结合上文。

0x03 业务范畴
我们在这里首先要讲讲几个业务范畴。

3.1 DataServer 数据一致性

为支持海量数据,SOFARegistry 采用了一致性 Hash 来分片存储 Publisher 数据,避免了单个服务器存储全量数据时产生的容量瓶颈问题。而在这个模型中,每个数据分片拥有多个副本,当存储注册数的 DataServer 进行扩容、缩容时,MetaServer 会把这个变更通知到 DataServer 和 SessionServer,数据分片会在集群内部进行数据迁移与同步,此时就出现了 DataServer 内部数据的一致性问题。

3.2 节点变更时的数据同步

MetaServer 会通过网络连接感知到新节点上线或者下线,所有的 DataServer 中运行着一个定时刷新连接的任务 ConnectionRefreshTask,该任务定时去轮询 MetaServer,获取数据节点的信息。需要注意的是,除了 DataServer 主动去 MetaServer 拉取节点信息外,MetaServer 也会主动发送 NodeChangeResult 请求到各个节点,通知节点信息发生变化,推拉获取信息的最终效果是一致的。

0x04 总体逻辑
这部分总体逻辑如下:

当轮询信息返回数据节点有变化时,会向 EventCenter 投递一个 DataServerChangeEvent 事件,在该事件的处理器中,如果判断出是当前机房节点信息有变化,则会投递新的事件 LocalDataServerChangeEvent。

该事件的处理器 LocalDataServerChangeEventHandler 中会判断当前节点是否为新加入的节点,如果是新节点则会向其它节点发送 NotifyOnlineRequest 请求,如图所示:

图 DataServer 节点上线时新节点的逻辑

本文就主要讲解从DataServerChangeEvent到LocalDataServerChangeEvent这部分的逻辑。

0x05 DataServerChangeEvent
5.1 消息来源

DataServerChangeEvent有三种来源:启动主动获取,定期,推送。这三种具体如下:

启动主动获取:这个主动查询并且拉取的过程,这个过程基本上类似一个同步过程,体现为客户端一次查询结果的同步返回。
版本变更推送:为了确定服务发布数据的变更,对于这个服务感兴趣的所有客户端订阅方都需要推送,进行推送。由于性能要求必须并发执行并且异步确定推送成功。
定期轮训:这样避免了某次变更通知没有通知到所有订阅方的情况。
因为有了上文的知识,我们应该知道,启动主动获取 和 推送 这两种方式是通过MetaServerChangeEvent完成的,结合上文逻辑图,现在简述如下:

±------------------------------+
|[DataServerBootstrap] | MetaServerChangeEvent
| |
| ±------------------------+
| startRaftClient | a |
| | | ±--------------+
| | | | |
±------------------------------+ | | |
±------------------------------+ | | |
| [Timer] | | v |
| | b | 1 ±------±----+ |
| ConnectionRefreshMetaTask ±-----------------------------> | EventCenter ±—+ |
| | MetaServerChangeEvent | ±------±----+ | |
±------------------------------+ | ^ | |
±------------------------------+ | | | |
| | | | | |
| [Push] | | | | |
| | c | | | |
| ±------------------------+ | | |
| | MetaServerChangeEvent | | |
| ServerChangeHandler | 2 | | |
| ±---------------------------------------+ | |
±------------------------------+ DataServerChangeEvent | |
| |
| |
MetaServerChangeEvent | |
3 | |
±---------------------------------------------------+ |
| |
v |
±----------------±-------------+ DataServerChangeEvent |
| | 4 |
| MetaServerChangeEventHandler ±-----------------------------------------+
| |
±-------------------------------+
5.1.1 启动

5.1.1.1 产生消息

当 DataServer 节点初始化成功后,会启动任务自动去连接 MetaServer。启动时,会从配置里面读取meta server配置,metaServerService.getMetaServerMap();据此构建MetaServerChangeEvent,投放到EventCenter之中。

private void startRaftClient() {
metaServerService.startRaftClient();
eventCenter.post(new MetaServerChangeEvent(metaServerService.getMetaServerMap()));
}
5.1.1.2 MetaServerChangeEventHandler

MetaServerChangeEventHandler 用来响应 MetaServerChangeEvent 消息。因为其继承了AbstractEventHandler,所以 MetaServerChangeEventHandler 已经注册到了EventCenter之上。

在处理MetaServerChangeEvent之后,该任务会往事件中心 EventCenter 注册一个 DataServerChangeEvent 事件,该事件注册后会被触发,之后将对新增节点计算 Hash 值,同时进行纳管分片。

就是对应上图 a,1,3,4这条线,是DataServerChangeEvent的来源1。

5.1.2 推送

这个来源是其他消息的转换,即NodeChangeResult的转换。而且有两个转换过程。

5.1.2.1 推送

除了 DataServer 主动去 MetaServer 拉取节点信息外,MetaServer 也会主动发送 NodeChangeResult 请求到各个节点,通知节点信息发生变化,推拉获取信息的最终效果是一致的。

5.1.2.2 第一层转换

ServerChangeHandler 是 metaClientHandler 的一部分,是MetaNodeExchanger 的响应函数。

在ServerChangeHandler之中,拿到了NodeChangeResult之后,会判断变更节点类型,这里会根据 Note 类型不同,决定产生 DataServerChangeEvent 还是 MetaServerChangeEvent。

如果是NodeType.META,就发送消息给eventCenter,即eventCenter.post(new MetaServerChangeEvent(map));,

这就是MetaServerChangeEvent和DataServerChangeEvent来源之一。就是对应上图2这条线,是DataServerChangeEvent的来源2。

public class ServerChangeHandler extends AbstractClientHandler {

@Autowired
private EventCenter         eventCenter;

@Autowired
private DataServerConfig    dataServerConfig;

@Override
public Object doHandle(Channel channel, NodeChangeResult request) {
    ExecutorFactory.getCommonExecutor().execute(() -> {
      
        if (request.getNodeType() == NodeType.DATA) {
          
            eventCenter.post(new DataServerChangeEvent(request.getNodes(),
                    request.getDataCenterListVersions(), FromType.META_NOTIFY));
          
        } else if (request.getNodeType() == NodeType.META) {
          
            Map> metaNodesMap = request.getNodes();
            if (metaNodesMap != null && !metaNodesMap.isEmpty()) {
                Map metaNodeMap = metaNodesMap.get(dataServerConfig.getLocalDataCenter());
                if (metaNodeMap != null && !metaNodeMap.isEmpty()) {
                    HashMap> map = new HashMap<>();
                    map.put(dataServerConfig.getLocalDataCenter(), metaNodeMap.keySet());
                    eventCenter.post(new MetaServerChangeEvent(map));
                }
            }
        }
    });
    return CommonResponse.buildSuccessResponse();
}

@Override
public Class interest() {
    return NodeChangeResult.class;
}

@Override
public HandlerType getType() {
    return HandlerType.PROCESSER;
}

@Override
protected Node.NodeType getConnectNodeType() {
    return Node.NodeType.DATA;
}

}
5.1.2.3 第二层转换

MetaServerChangeEventHandler 用来响应 MetaServerChangeEvent 消息。因为其继承了AbstractEventHandler,所以 MetaServerChangeEventHandler 已经注册到了EventCenter之上。

注意,这里有一个再次转换DataServerChangeEvent的过程,即MetaServerChangeEventHandler这里会再主动和MetaServer交互,这是因为Meta Server的这个推送,也许是在告诉data Server,“hi,目前data server也有变动”。

如果返回消息是NodeChangeResult,就转换为DataServerChangeEvent,投放DataServerChangeEvent到Event Center。

就是对应上图 b,1,3,4这条线,是DataServerChangeEvent的来源3。

public class MetaServerChangeEventHandler extends AbstractEventHandler {
private void registerMetaServer(String dataCenter, String ip) {

if (obj instanceof NodeChangeResult) {
NodeChangeResult result = (NodeChangeResult) obj;
Map versionMap = result.getDataCenterListVersions();

                    //send renew after first register dataNode
                    Set set = new HashSet<>();
                    set.add(StartTaskTypeEnum.RENEW);
                    eventCenter.post(new StartTaskEvent(set));

                    eventCenter.post(new DataServerChangeEvent(result.getNodes(), versionMap,
                            DataServerChangeEvent.FromType.REGISTER_META));
                    break;
                }
}

}
0x06 轮训拉
我们这里要重点讲解DataServerChangeEvent的来源“轮训拉”。

MetaServer 会通过网络连接感知到新节点上线或者下线,所有的 DataServer 中运行着一个定时刷新连接的任务 ConnectionRefreshTask,该任务定时去轮询 MetaServer,获取数据节点的信息。

6.1 Bean

ConnectionRefreshTask 在 tasks 这个 Bean中启动。

@Bean(name = “tasks”)
public List tasks() {
List list = new ArrayList<>();
list.add(connectionRefreshTask());
list.add(connectionRefreshMetaTask());
list.add(renewNodeTask());
return list;
}
6.2 启动

tasks是在startScheduler间接启动的。

eventCenter.post(new StartTaskEvent(
Arrays.stream(StartTaskTypeEnum.values()).filter(type -> type != StartTaskTypeEnum.RENEW).collect(Collectors.toSet())));
StartTaskEventHandler响应StartTaskEvent,其会逐一启动tasks。

public class StartTaskEventHandler extends AbstractEventHandler {

@Resource(name = "tasks")
private List       tasks;

private ScheduledExecutorService executor     = null;

@Override
public void doHandle(StartTaskEvent event) {
    if (executor == null || executor.isShutdown()) {
        getExecutor();
    }

    for (AbstractTask task : tasks) {
        if (event.getSuitableTypes().contains(task.getStartTaskTypeEnum())) {
            executor.scheduleWithFixedDelay(task, task.getInitialDelay(), task.getDelay(),
                task.getTimeUnit());
        }
    }
}

private void getExecutor() {
    executor = ExecutorFactory.newScheduledThreadPool(tasks.size(), this.getClass()
        .getSimpleName());
}

}
这里有一个技巧。

ConnectionRefreshTask里面指定了支持CONNECT_DATA,StartTaskEventHandler在启动时判断支持类型,发现是CONNECT_DATA,就启动了ConnectionRefreshTask。

AbstractEventHandler 其中注册了eventCenter.register,这样它的继承类都默认注册到了EventCenter 之上。

public abstract class AbstractEventHandler implements InitializingBean {
@Autowired
private EventCenter eventCenter;

@Override
public void afterPropertiesSet() throws Exception {
    eventCenter.register(this);
}

/**
 * event handle func
 * @param event
 */
public void handle(Event event) {
        doHandle(event);
}

public abstract List> interest();

public abstract void doHandle(Event event);

}
于是,connectionRefreshTask就启动了。

6.3 ConnectionRefreshTask

ConnectionRefreshTask负责轮询与meta Server交互,可以看到,也发送了DataServerChangeEvent。

public class ConnectionRefreshTask extends AbstractTask {

@Autowired
private IMetaServerService metaServerService;

@Autowired
private EventCenter        eventCenter;

@Override
public void handle() {
    DataServerChangeItem dataServerChangeItem = metaServerService.getDateServers();
    if (dataServerChangeItem != null) {
        eventCenter
            .post(new DataServerChangeEvent(dataServerChangeItem, FromType.CONNECT_TASK));
    }
}

@Override
public int getDelay() {
    return 30;
}

@Override
public int getInitialDelay() {
    return 0;
}

@Override
public TimeUnit getTimeUnit() {
    return TimeUnit.SECONDS;
}

@Override
public StartTaskTypeEnum getStartTaskTypeEnum() {
    return StartTaskTypeEnum.CONNECT_DATA;
}

}
ConnectionRefreshTask 调用 metaServerService.getDateServers();getDateServers 的作用是:

从 metaServerConnectionFactory 获取connectionMap;
通过raft来获取raft leader;
从 connectionMap 获取 leader 的connection,这是一个 bolt Connection;
利用 bolt Connection 进行请求,GetNodesRequest(NodeType.DATA);
从请求结果构建 DataServerChangeItem;
在 EventCenter 中放一个消息 DataServerChangeEvent(dataServerChangeItem, FromType.CONNECT_TASK);
具体如下:

@Override
public DataServerChangeItem getDateServers() {
Map connectionMap = metaServerConnectionFactory
.getConnections(dataServerConfig.getLocalDataCenter());
String leader = getLeader().getIp();
if (connectionMap.containsKey(leader)) {
Connection connection = connectionMap.get(leader);
if (connection.isFine()) {
try {
GetNodesRequest request = new GetNodesRequest(NodeType.DATA);
Object obj = metaNodeExchanger.request(new Request() {
@Override
public Object getRequestBody() {
return request;
}

                @Override
                public URL getRequestUrl() {
                    return new URL(connection.getRemoteIP(), connection.getRemotePort());
                }
            }).getResult();
            if (obj instanceof NodeChangeResult) {
                NodeChangeResult result = (NodeChangeResult) obj;
                Map versionMap = result.getDataCenterListVersions();
                versionMap.put(result.getLocalDataCenter(), result.getVersion());
                return new DataServerChangeItem(result.getNodes(), versionMap);
            }
        } 
    }
}
String newip = refreshLeader().getIp();
return null;

}
0x07 DataServerChangeEventHandler
7.1 总体逻辑

DataServerChangeEvent 事件被触发后,由 DataServerChangeEventHandler 来进行相应的处理,分别分为如下一些步骤:

初始化当前数据节点的一致性 Hash 值,把当前节点添加进一致性的 Hash 环中。
获取变更了的 DataServer 节点,这些节点在启动 DataServer 服务的时候从 MetaServer 中获取到的,并且通过 DataServerChangeEvent 事件中的 DataServerChangeItem 传入。
获取了当前的 DataServer 节点之后,若节点列表非空,则遍历每个节点,建立当前节点与其余数据节点之间的连接,同时删除本地维护的不在节点列表中的节点数据,更新dataServerCache。同时,若当前节点是 DataCenter 节点,则触发 LocalDataServerChangeEvent 事件。
SOFA这里主要是处理LocalDataServerChangeEvent,异地机房的部分没有开源。

7.2 LocalDataServerChangeEvent

关于上面第三点,详细说明如下:

从DataServerChangeEvent中提取DataServerChangeItem,如果发现有一个DataCenter就是本机,则使用如下语句获取新加入的DataServer。

Set newjoined = new HashSet<>(ips);
newjoined.removeAll(localDataServers);
然后使用这些新加入的DataServer来构建 LocalDataServerChangeEvent。

参见如下片段:

//get changed dataservers
Map changedMap = dataServerCache.compareAndSet(
dataServerChangeItem, event.getFromType());
if (!changedMap.isEmpty()) {
for (Entry changeEntry : changedMap.entrySet()) {
String dataCenter = changeEntry.getKey();
Set ips = changeEntry.getValue();

	String dataCenter = changeEntry.getKey();
Set ips = changeEntry.getValue();

//if the dataCenter is self, post LocalDataServerChangeEvent
if (dataServerConfig.isLocalDataCenter(dataCenter)) {
    Set newjoined = new HashSet<>(ips);
    newjoined.removeAll(localDataServers);
    eventCenter.post(new LocalDataServerChangeEvent(map, newjoined,
        dataServerChangeItem.getVersionMap().get(dataCenter), newVersion));
} else {
    dataServerCache.updateItem(newDataNodes, newVersion, dataCenter);
    eventCenter.post(new RemoteDataServerChangeEvent(dataCenter, map,
        dataServerChangeItem.getVersionMap().get(dataCenter), newVersion));
}

}
具体代码如下:

public class DataServerChangeEventHandler extends AbstractEventHandler {

private static final int    TRY_COUNT = 5;

@Autowired
private DataServerConfig    dataServerConfig;

@Autowired
private DataServerCache     dataServerCache;

@Autowired
private DataNodeExchanger   dataNodeExchanger;

@Autowired
private EventCenter         eventCenter;

@Override
public List> interest() {
    return Lists.newArrayList(DataServerChangeEvent.class);
}

@Override
public void doHandle(DataServerChangeEvent event) {
    synchronized (this) {
        //register self first,execute once
        DataServerNodeFactory.initConsistent(dataServerConfig);

        DataServerChangeItem dataServerChangeItem = event.getDataServerChangeItem();
        Set localDataServers = dataServerCache.getDataServers(
            dataServerConfig.getLocalDataCenter()).keySet();
      
        //get changed dataservers 得到变化了的dataServers
        Map> changedMap = dataServerCache.compareAndSet(
            dataServerChangeItem, event.getFromType());
      
        if (!changedMap.isEmpty()) {
            for (Entry> changeEntry : changedMap.entrySet()) {
                String dataCenter = changeEntry.getKey();
                Set ips = changeEntry.getValue();
                Long newVersion = dataServerCache.getDataCenterNewVersion(dataCenter);
                if (!CollectionUtils.isEmpty(ips)) {
                    for (String ip : ips) {
                        if (!StringUtils.equals(ip, DataServerConfig.IP)) {
                            DataServerNode dataServerNode = DataServerNodeFactory
                                .getDataServerNode(dataCenter, ip);
                            if (dataServerNode == null
                                || dataServerNode.getConnection() == null
                                || !dataServerNode.getConnection().isFine()) {
                                connectDataServer(dataCenter, ip);
                            }
                        }
                    }
                    //remove all old DataServerNode not in change map
                    Set ipSet = DataServerNodeFactory.getIps(dataCenter);
                    for (String ip : ipSet) {
                        if (!ips.contains(ip)) {
                            DataServerNodeFactory.remove(dataCenter, ip, dataServerConfig);
                        }
                    }

                    Map newDataNodes = dataServerCache
                        .getNewDataServerMap(dataCenter);

                    //avoid input map reference operation DataServerNodeFactory MAP
                    Map map = new ConcurrentHashMap<>(newDataNodes);

                    //if the dataCenter is self, post LocalDataServerChangeEvent
                    if (dataServerConfig.isLocalDataCenter(dataCenter)) {
                      //为什么 local 时候不做 updateItem
                        Set newjoined = new HashSet<>(ips);
                        newjoined.removeAll(localDataServers);
                        eventCenter.post(new LocalDataServerChangeEvent(map, newjoined,
                            dataServerChangeItem.getVersionMap().get(dataCenter), newVersion));
                    } else {
                        dataServerCache.updateItem(newDataNodes, newVersion, dataCenter);
                        eventCenter.post(new RemoteDataServerChangeEvent(dataCenter, map,
                            dataServerChangeItem.getVersionMap().get(dataCenter), newVersion));
                    }
                } else {
                    //if the dataCenter which has no dataServers is not self, remove it
                    if (!dataServerConfig.isLocalDataCenter(dataCenter)) {
                        removeDataCenter(dataCenter);
                        eventCenter.post(new RemoteDataServerChangeEvent(dataCenter,
                            Collections.EMPTY_MAP, dataServerChangeItem.getVersionMap().get(
                                dataCenter), newVersion));
                    }
                    Map newDataNodes = dataServerCache
                        .getNewDataServerMap(dataCenter);
                    dataServerCache.updateItem(newDataNodes, newVersion, dataCenter);
                }
            }
        } else {
            //refresh for keep connect other dataServers
            //如果没有“有变化”的DataServer,则重新连接一下现有的DataServer
            Set allDataCenter = new HashSet<>(dataServerCache.getAllDataCenters());
            for (String dataCenter : allDataCenter) {
                Map dataNodes = dataServerCache
                    .getNewDataServerMap(dataCenter);
                if (dataNodes != null) {
                    for (DataNode dataNode : dataNodes.values()) {
                        if (!StringUtils.equals(dataNode.getIp(), DataServerConfig.IP)) {
                            DataServerNode dataServerNode = DataServerNodeFactory
                                .getDataServerNode(dataCenter, dataNode.getIp());
                            Connection connection = dataServerNode != null ? dataServerNode
                                .getConnection() : null;
                            if (connection == null || !connection.isFine()) {
                                connectDataServer(dataCenter, dataNode.getIp());
                            }
                        }
                    }
                }
            }
        }
    }
}

/**
 * connect specific dataserver
 *
 * @param dataCenter
 * @param ip
 */
private void connectDataServer(String dataCenter, String ip) {
    Connection conn = null;
    for (int tryCount = 0; tryCount < TRY_COUNT; tryCount++) {
        try {
            conn = ((BoltChannel) dataNodeExchanger.connect(new URL(ip, dataServerConfig
                .getSyncDataPort()))).getConnection();
            break;
        } catch (Exception e) {
            TimeUtil.randomDelay(3000);
        }
    }
    if (conn == null || !conn.isFine()) {
        throw new RuntimeException(
            String
                .format(
                    "[DataServerChangeEventHandler] connect dataServer %s in %s failed five times,dataServer will not work,please check connect!",
                    ip, dataCenter));
    }
    //maybe get dataNode from metaServer,current has not start! register dataNode info to factory,wait for connect task next execute
    DataServerNodeFactory.register(new DataServerNode(ip, dataCenter, conn), dataServerConfig);
}

/**
 * remove dataCenter, and close connections of dataServers in this dataCenter
 *
 * @param dataCenter
 */
private void removeDataCenter(String dataCenter) {
    DataServerNodeFactory.getDataServerNodes(dataCenter).values().stream().map(DataServerNode::getConnection)
            .filter(connection -> connection != null && connection.isFine()).forEach(Connection::close);
    DataServerNodeFactory.remove(dataCenter);
}

}
7.3 逻辑图

于是,我们的逻辑图拓展如下:

DataServerChangeEvent一共四个来源。

前三个来源是与MetaServerChangeEvent相关。

启动主动获取:MetaServerChangeEventHandler 用来响应 MetaServerChangeEvent 消息。在处理MetaServerChangeEvent之后,该任务会往事件中心 EventCenter 注册一个 DataServerChangeEvent 事件。就是对应下图 a,1,3,4这条线,是DataServerChangeEvent的来源1。
版本变更推送:ServerChangeHandler 是 MetaNodeExchanger 的响应函数。在ServerChangeHandler之中,拿到了NodeChangeResult之后,会判断变更节点类型,这里会根据 Note 类型不同,决定产生 DataServerChangeEvent 还是 MetaServerChangeEvent。
如果是NodeType.DATA,ServerChangeHandler 就发送消息给eventCenter,即eventCenter.post(new MetaServerChangeEvent(map));;就是对应下图2这条线,是DataServerChangeEvent的来源2。
如果是NodeType.DATA,ServerChangeHandler 就发送消息给eventCenter,即eventCenter.post(new MetaServerChangeEvent(map));;注意,这里有一个再次转换DataServerChangeEvent的过程,即MetaServerChangeEventHandler这里会再主动和MetaServer交互,如果返回消息是NodeChangeResult,就转换为DataServerChangeEvent,投放DataServerChangeEvent到Event Center。就是对应下图 b,1,3,4这条线,是DataServerChangeEvent的来源3。
第四来源是定期轮训。

所有的 DataServer 中运行着一个定时刷新连接的任务 ConnectionRefreshTask,该任务定时去轮询 MetaServer,获取数据节点的信息。

ConnectionRefreshTask 调用 metaServerService.getDateServers();与MetaServer联系,从请求结果构建 DataServerChangeItem;在 EventCenter 中放一个消息 DataServerChangeEvent(dataServerChangeItem, FromType.CONNECT_TASK);就是对应下图5这条线,是DataServerChangeEvent的来源3。

最后,DataServerChangeEvent 事件被触发后,由 DataServerChangeEventHandler 来进行相应的处理。就是对应下图6,7这条线。

若当前节点是 DataCenter 节点,则触发 LocalDataServerChangeEvent 事件。SOFA这里主要是处理LocalDataServerChangeEvent,异地机房的部分没有开源。

±--------------------------+
|[DataServerBootstrap] | MetaServerChangeEvent ±-----------------------+
| | | |
| ±------------------------+ | ±-----------------+ |
| startRaftClient | a | | | | |
| | | | | ±------------+ | |
| | | | | | | | |
±--------------------------+ | | | | | | |
±--------------------------+ | v | | | | |
| [Timer] | | | v | | |
| | b | 1 ±—±-±----+ | | |
| ConnectionRefreshMetaTask ±-----------------------------> | EventCenter ±—+ | | |
| | MetaServerChangeEvent | ±------±–±+ | | | |
±--------------------------+ | ^ ^ | | | |
±--------------------------+ | | | | | | |
| | | | | | | | |
| [Push] | | | | | | | |
| | c | | | | | | |
| ±------------------------+ | | 5 | | | |
| | MetaServerChangeEvent | | | | | |
| ServerChangeHandler | 2 | | | | | |
| ±---------------------------------------+ | | | | |
±--------------------------+ DataServerChangeEvent | | | | |
| | | | |
±------------------------+ | | | | |
| | | | | | |
| ConnectionRefreshTask ±---------------------------------------------+ | | | |
| | | | | |
±------------------------+ | | | |
| | | |
MetaServerChangeEvent | | | |
3 | | | |
±---------------------------------------------------+ | | |
| | | |
v | | |
±----------------±-------------+ DataServerChangeEvent | | |
| | 4 | | |
| MetaServerChangeEventHandler ±---------------------------------------+ | |
| | | |
±-------------------------------+ | |
| |
DataServerChangeEvent | |
±-----------------------------+ | |
| DataServerChangeEventHandler | <----------------------------------------+ |
±--------------±-------------+ 6 |
| |
| 7 |
±-----------------------------------------------------------+
LocalDataServerChangeEvent / RemoteDataServerChangeEvent
0x08 总结
本文讲解了SOFARegistry如何处理Data节点变化。

主要就是从DataServerChangeEvent到LocalDataServerChangeEvent这部分的逻辑。SOFA这里主要是处理LocalDataServerChangeEvent,异地机房的部分没有开源。所以下文我们介绍LocalDataServerChangeEvent。

0xFF 参考
蚂蚁金服服务注册中心如何实现 DataServer 平滑扩缩容

蚂蚁金服服务注册中心 SOFARegistry 解析 | 服务发现优化之路

服务注册中心 Session 存储策略 | SOFARegistry 解析

海量数据下的注册中心 - SOFARegistry 架构介绍

服务注册中心数据分片和同步方案详解 | SOFARegistry 解析

蚂蚁金服开源通信框架SOFABolt解析之连接管理剖析

蚂蚁金服开源通信框架SOFABolt解析之超时控制机制及心跳机制

蚂蚁金服开源通信框架 SOFABolt 协议框架解析

蚂蚁金服服务注册中心数据一致性方案分析 | SOFARegistry 解析

★★★★★★关于生活和技术的思考★★★★★★
微信公众账号:罗西的思考
如果您想及时得到个人撰写文章的消息推送,或者想看看个人推荐的技术资料,可以扫描下面二维码(或者长按识别二维码)关注个人公众号)。

分类: 210_SOFAStack, 008_微服务, 005_源码分析
好文要顶 关注我 收藏该文
罗西的思考
关注 - 0
粉丝 - 23
+加关注
0 0
« 上一篇: [从源码学设计]蚂蚁金服SOFARegistry 之 如何与Meta Server交互
posted @ 2020-12-26 11:13 罗西的思考 阅读(68) 评论(0) 编辑 收藏
刷新评论刷新页面返回顶部
登录后才能发表评论,立即 登录 或 注册, 访问 网站首页
写给园友们的一封求助信
【推荐】News: 大型组态、工控、仿真、CADGIS 50万行VC++源码免费下载
【推荐】有你助力,更好为你——博客园用户消费观调查,附带小惊喜!
【推荐】博客园x丝芙兰-圣诞特别活动:圣诞选礼,美力送递
【推荐】了不起的开发者,挡不住的华为,园子里的品牌专区
【福利】AWS携手博客园为开发者送免费套餐+50元京东E卡
【推荐】未知数的距离,毫秒间的传递,声网与你实时互动
【推荐】新一代 NoSQL 数据库,Aerospike专区新鲜入驻

相关博文:
· 学习Spring-Data-Jpa(十五)—Auditing与@MappedSuperclass
· string::data
· 学习Spring-Data-Jpa(十六)—@Version与@Lock
· SpringDataJPA
· 论文翻译:Dataminingwithbigdata
» 更多推荐…

最新 IT 新闻:
· 熬过2020,我的公司还活着
· 一夜之间,两家A股网游上市公司实控人出大事了!
· 苹果造车,到底有没有戏?
· 玩了10小时《赛博朋克2077》 我觉得很失望
· 一文读懂2020年大厂如何调整组织架构
» 更多新闻…
公告
★关于生活和技术的思考★
欢迎关注公众号,您将会得到及时的文章推送信息:

昵称: 罗西的思考
园龄: 1年1个月
粉丝: 23
关注: 0
+加关注
< 2020年12月 >
日 一 二 三 四 五 六
29 30 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
3 4 5 6 7 8 9
搜索

找找看

谷歌搜索
常用链接
我的随笔
我的评论
我的参与
最新评论
我的标签
随笔分类
001_机器学习(37)
002_大数据(43)
003_白话解析(17)
004_项目记录(14)
005_源码分析(49)
006_Android(1)
007_梁山好汉说IT(18)
008_微服务(21)
009_笔记整理(1)
010_业界方案(12)
011_AIOps(1)
012_工具使用(1)
013_论文阅读(12)
014_推荐系统(12)
015_深度学习(12)
更多
随笔档案
2020年12月(8)
2020年11月(9)
2020年10月(9)
2020年9月(9)
2020年8月(15)
2020年7月(15)
2020年6月(17)
2020年5月(6)
2020年4月(4)
2020年3月(5)
2020年2月(3)
2020年1月(6)
2019年12月(1)
2019年11月(5)
2019年10月(1)
最新评论

  1. Re:[业界方案] 智能运维AIOps-学习笔记
    推荐一个AIOps软件,OpManager运用人工智能技术,在繁杂的信息中以更便捷的方式得到高效的洞察.快速响应IT运维问题,判定故障根因,评价业务价值,预测业务风险,并提升数字化体验…
    –Zoho_IT爱好者
  2. Re:[白话解析] 深入浅出支持向量机(SVM)之核函数
    大佬
    –半勺白糖
  3. Re:[论文阅读]阿里DIN深度兴趣网络之总体解读
    学习,学习
    –河北泊腾
  4. Re:[记录点滴]授人以渔,从Tensorflow找不到dll扩展到如何排查问题
    666
    –Ajanuw
  5. Re:[源码解析] Flink的Slot究竟是什么?(2)
    阿里云业务支撑中台招人啦!在ToB风口上,业务快速发展,技术上充满挑战,个人成长空间大;客观上,团队绩效好,发展快。地点-北京,岗位-Java服务端研发/数据研发 (高级)技术专家或高级工程师,期待您…
    –杨柳岸,晓风残月
    阅读排行榜
  6. [白话解析] Flink的Watermark机制(7153)
  7. [白话解析] 深入浅出最大熵模型(2868)
  8. [源码分析] 带你梳理 Flink SQL / Table API内部执行流程(1537)
  9. [源码分析] 从FlatMap用法到Flink的内部实现(1436)
  10. [源码分析] 从源码入手看 Flink Watermark 之传播过程(1429)
    评论排行榜
  11. Alink漫谈(一) : 从KMeans算法实现不同看Alink设计思想(3)
  12. [论文阅读]阿里DIN深度兴趣网络之总体解读(1)
  13. [记录点滴]授人以渔,从Tensorflow找不到dll扩展到如何排查问题(1)
  14. [源码解析] Flink的Slot究竟是什么?(2)(1)
  15. Alink漫谈(二十) :卡方检验源码解析(1)
    推荐排行榜
  16. Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构(3)
  17. [白话解析] Flink的Watermark机制(3)
  18. [白话解析]以水浒传为例学习隐马尔可夫模型(2)
  19. [业界方案]用Jaeger来学习分布式追踪系统Opentracing(1)
  20. [源码解析] Flink的Slot究竟是什么?(2)(1)
    Copyright © 2020 罗西的思考
    Powered by .NET 5.0.1-servicing.20575.16 on Kubernetes

你可能感兴趣的:(2020-12-26)