Nacos服务端-集群同步状态
Nacos-server
搭建集群时,集群中的每个server
要互相同步状态,以便及时感知集群中的节点状态情况,前面几章中很多地方有 Responsible(servicename)
是否对 service负责
的判断,就需要用到节点的数量
本章代码入口在 ServerListManager
的初始化方法中,有两个线程会执行,分别是 ServerStatusReport
和 ServerInfoUpdater
ServerStatusReporter
public void run() {
try {
if (EnvUtil.getPort() <= 0) {
return;
}
// 获取机器的核心数 / 2
int weight = Runtime.getRuntime().availableProcessors() / 2;
// 如果是1核,weight = 0,设置为1
if (weight <= 0) {
weight = 1;
}
long curTime = System.currentTimeMillis();
// 构造一串字符串
String status = LOCALHOST_SITE + "#" + EnvUtil.getLocalAddress() + "#" + curTime + "#" + weight
+ "\r\n";
// 获取所有的server信息
List<Member> allServers = getServers();
// 如果不包含本server, return
if (!contains(EnvUtil.getLocalAddress())) {
Loggers.SRV_LOG.error("local ip is not in serverlist, ip: {}, serverlist: {}",
EnvUtil.getLocalAddress(), allServers);
return;
}
if (allServers.size() > 0 && !EnvUtil.getLocalAddress()
.contains(IPUtil.localHostIP())) {
// 遍历所有的server
for (Member server : allServers) {
// 排除本server
if (Objects.equals(server.getAddress(), EnvUtil.getLocalAddress())) {
continue;
}
// This metadata information exists from 1.3.0 onwards "version"
if (server.getExtendVal(MemberMetaDataConstants.VERSION) != null) {
Loggers.SRV_LOG
.debug("[SERVER-STATUS] target {} has extend val {} = {}, use new api report status",
server.getAddress(), MemberMetaDataConstants.VERSION,
server.getExtendVal(MemberMetaDataConstants.VERSION));
continue;
}
Message msg = new Message();
msg.setData(status);
// 调用其他server接口,这里会调用ServerStatusSynchronizer实现类
synchronizer.send(server.getAddress(), msg);
}
}
} catch (Exception e) {
Loggers.SRV_LOG.error("[SERVER-STATUS] Exception while sending server status", e);
} finally {
GlobalExecutor
.registerServerStatusReporter(this, switchDomain.getServerStatusSynchronizationPeriodMillis());
}
}
public void send(final String serverIP, Message msg) {
if (StringUtils.isEmpty(serverIP)) {
return;
}
final Map<String, String> params = new HashMap<String, String>(2);
params.put("serverStatus", msg.getData());
String url = "http://" + serverIP + ":" + EnvUtil.getPort() + EnvUtil.getContextPath()
+ UtilsAndCommons.NACOS_NAMING_CONTEXT + "/operator/server/status";
if (IPUtil.containsPort(serverIP)) {
url = "http://" + serverIP + EnvUtil.getContextPath() + UtilsAndCommons.NACOS_NAMING_CONTEXT
+ "/operator/server/status";
}
try {
// GET调用/v1/ns/operator/server/status
HttpClient.asyncHttpGet(url, null, params, new Callback<String>() {
@Override
public void onReceive(RestResult<String> result) {
if (!result.ok()) {
Loggers.SRV_LOG.warn("[STATUS-SYNCHRONIZE] failed to request serverStatus, remote server: {}",
serverIP);
}
}
@Override
public void onError(Throwable throwable) {
Loggers.SRV_LOG.warn("[STATUS-SYNCHRONIZE] failed to request serverStatus, remote server: {}", serverIP, throwable);
}
@Override
public void onCancel() {
}
});
} catch (Exception e) {
Loggers.SRV_LOG.warn("[STATUS-SYNCHRONIZE] failed to request serverStatus, remote server: {}", serverIP, e);
}
}
再看看调用的这个接口,在 OperatorController
中
@RequestMapping("/server/status")
public String serverStatus(@RequestParam String serverStatus) {
serverListManager.onReceiveServerStatus(serverStatus);
return "ok";
}
public boolean update(Member newMember) {
Loggers.CLUSTER.debug("member information update : {}", newMember);
String address = newMember.getAddress();
// 如果本地serverList不包含该地址
if (!serverList.containsKey(address)) {
return false;
}
// 更新server信息到serverList
serverList.computeIfPresent(address, (s, member) -> {
// 如果新member的状态为DOWN
if (NodeState.DOWN.equals(newMember.getState())) {
// 从memberAddressInfos中移除该member的地址
memberAddressInfos.remove(newMember.getAddress());
}
// 判断是否改变信息
boolean isPublishChangeEvent = MemberUtil.isBasicInfoChanged(newMember, member);
// 设置最后刷新事件
newMember.setExtendVal(MemberMetaDataConstants.LAST_REFRESH_TIME, System.currentTimeMillis());
// 对象赋值 newMember-> member(旧)
MemberUtil.copy(newMember, member);
// 是否改变信息
if (isPublishChangeEvent) {
// member basic data changes and all listeners need to be notified
// 发布MembersChangeEvent
notifyMemberChange();
}
return member;
});
return true;
}
void notifyMemberChange() {
NotifyCenter.publishEvent(MembersChangeEvent.builder().members(allMembers()).build());
}
ServerInfoUpdater
public void run() {
List<Member> members = servers;
if (members.isEmpty()) {
return;
}
// 轮询获取下一个server
this.cursor = (this.cursor + 1) % members.size();
Member target = members.get(cursor);
if (Objects.equals(target.getAddress(), EnvUtil.getLocalAddress())) {
return;
}
// This metadata information exists from 1.3.0 onwards "version"
if (target.getExtendVal(MemberMetaDataConstants.VERSION) != null) {
return;
}
// 构造url: /operator/cluster/state
final String path =
UtilsAndCommons.NACOS_NAMING_OPERATOR_CONTEXT + UtilsAndCommons.NACOS_NAMING_CLUSTER_CONTEXT
+ "/state";
final Map<String, String> params = Maps.newHashMapWithExpectedSize(2);
// 目标server地址
final String server = target.getAddress();
try {
// 发起调用
String content = NamingProxy.reqCommon(path, params, server, false);
if (!StringUtils.EMPTY.equals(content)) {
RaftPeer raftPeer = JacksonUtils.toObj(content, RaftPeer.class);
if (null != raftPeer) {
String json = JacksonUtils.toJson(raftPeer);
Map map = JacksonUtils.toObj(json, HashMap.class);
target.setExtendVal("naming", map);
// 更新信息到本地
memberManager.update(target);
}
}
} catch (Exception ignore) {
//
}
}
p.class);
target.setExtendVal("naming", map);
// 更新信息到本地
memberManager.update(target);
}
}
} catch (Exception ignore) {
//
}
}