Nacos2.0原理解析(⼆):寻址机制
什么是Nacos的寻址机制?
Nacos ⽀持单机部署以及集群部署,针对单机模式,Nacos 只是⾃⼰和⾃⼰通信;对于集群模式,则集群内的每个 Nacos 成员都需要相互通信。因此这就带来⼀个问题,该以何种⽅式去管理集群内的 Nacos 成员节点信息,这就是 Nacos 内部的寻址机制。
源码分析
寻址初始化
在Nacos中,ServerMemberManager 类存储着本节点所知道的所有成员节点列表信息,提供了针对成员节点的增删改查操作,同时维护了⼀个 MemberLookup 列表,⽅便进⾏动态切换成员节点寻址⽅式,是寻址逻辑的核⼼。
⾸先看ServerMemberManager类中的初始化⽅法init()。主要负责⼀些基本的设置、发布MembersChangeEvent事件并订阅IPChangeEvent事件,初始化寻址模式适配器并启动。
protected void init()throws NacosException {
Loggers.CORE.info("Nacos-related cluster resource initialization");
this.port = Property(SERVER_PORT_PROPERTY, Integer.class, DEFAULT_SERVER_PORT);
this.localAddress = SelfIP()+":"+ port;
this.lf = MemberUtil.singlePar(this.localAddress);
this.lf.tExtendVal(MemberMetaDataConstants.VERSION, VersionUtils.version);
// init abilities.
this.lf.tAbilities(initMemberAbilities());
rverList.Address(), lf);
northkorea//发布MembersChangeEvent事件并订阅IPChangeEvent事件
// register NodeChangeEvent publisher to NotifyManager
registerClusterEvent();
//初始化寻址模式适配器并启动
// Initializes the lookup mode
initAndStartLookup();
if(rverList.isEmpty()){
damn什么意思throw new NacosException(NacosException.SERVER_ERROR,"cannot get rverlist, so exit.");
}
Loggers.CORE.info("The cluster resource is initialized");
sob什么意思}
⾸先看registerClusterEvent⽅法,发布了MembersChangeEvent事件,订阅了订阅IPChangeEvent事件,事件触发后回调onEvent⽅法,将节点的属性赋上更新后的值。
private void registerClusterEvent(){
//发布MembersChangeEvent事件
// Register node change events
DEFAULT_MEMBER_CHANGE_EVENT_QUEUE_SIZE));
//订阅IPChangeEvent事件
// The address information of this node needs to be dynamically modified
// when registering the IP change of this node
@Override
public void onEvent(InetUtils.IPChangeEvent event){
String newAddress = NewIP()+":"+ port;
ServerMemberManager.this.localAddress = newAddress;
EnvUtil.tLocalAddress(localAddress);
Member lf = ServerMemberManager.this.lf;
lf.NewIP());
String oldAddress = OldIP()+":"+ port;
ServerMemberManager.ve(oldAddress);
ServerMemberManager.this.rverList.put(newAddress, lf);
ve(oldAddress);
berAddressInfos.add(newAddress);
}
@Override
public Class<?extends Event>subscribeType(){
return InetUtils.IPChangeEvent.class;
}
});
}
然后看initAndStartLookup⽅法,该⽅法进⾏寻址模式适配器的初始化与启动,寻址模式包括单机寻址、⽂件寻址、地址服务器寻址。
private void initAndStartLookup()throws NacosException {
厌学心理
软件培训机构//获取寻址模式适配器
this.lookup = ateLookUp(this);
isUAddressServer =this.lookup.uAddressServer();
//适配器启动
this.lookup.start();
}
先看createLookUp⽅法,查看获取适配器的逻辑,寻址模式通过LOOKUP_MODE_TYPE静态变量表⽰
的"pe"指定,取值为“file”或者“address-rver”,也就是⽂件寻址和地址服务器寻址。
public static MemberLookup createLookUp(ServerMemberManager memberManager)throws NacosException {
if(!StandaloneMode()){
String lookupType = Property(LOOKUP_MODE_TYPE);
LookupType type =chooLookup(lookupType);
LOOK_UP =find(type);
currentLookupType = type;
}el{
LOOK_UP =new StandaloneMemberLookup();
}
//给寻址适配器注⼊ServerMemberManager对象,⽅便利⽤ ServerMemberManager 的存储、查询能⼒
LOOK_UP.injectMemberManager(memberManager);
Loggers.CLUSTER.info("Current addressing mode lection : {}", Class().getSimpleName());
return LOOK_UP;
}
寻址机制的实现
1. 单机寻址
单机寻址对应StandaloneMemberLookup类,查看核⼼的doStart⽅法。单机模式的寻址模式很简单,就是找到⾃⼰的IP:PORT组合信息,然后格式化为⼀个节点信息,调⽤afterLookup 然后将信息存储到 ServerMemberManager 中。
public void doStart(){
String url = SelfIP()+":"+ Port();
adServerConf(Collections.singletonList(url)));
}
2. ⽂件寻址
⽂件寻址模式就是每个 Nacos 节点需要维护⼀个叫做 f 的⽂件,其中填写了每个成员节点的 IP 信息。
⽂件寻址对应FileConfigMemberLookup类,查看核⼼的doStart⽅法。调⽤readClusterConfFromDisk
⽅法读取本节点的f ⽂件,获取保存的节点成员列表。并注册FileWatcher监听f的变化,有变更会被监听并更新缓存地址列表。
public void doStart()throws NacosException {
readClusterConfFromDisk();
// U the inotify mechanism to monitor file changes and automatically
// trigger the reading f
try{
}catch(Throwable e){
("An exception occurred in the launch file monitor : {}", e.getMessage());
}
}
查看readClusterConfFromDisk⽅法。从磁盘中的f⽂件⾥读取节点列表并存储到 ServerMemberManager 中。
private void readClusterConfFromDisk(){
Collection<Member> tmpMembers =new ArrayList<>();
try{
//从磁盘⽂件中读取节点列表
List<String> tmp = adClusterConf();
tmpMembers = adServerConf(tmp);
}catch(Throwable e){
Loggers.CLUSTER
.error("nacos-XXXX [rverlist] failed to get rverlist from disk!, error : {}", e.getMessage());
}
美工设计培训中心
//将节点列表信息存储到 ServerMemberManager 中。
afterLookup(tmpMembers);
}
查看注册的监听器FileWatcher,监听器会⾃动发现⽂件修改,重新读取⽂件内容、加载 IP 列表信息、更新新增的节点。
private FileWatcher watcher =new FileWatcher(){
@Override
public void onChange(FileChangeEvent event){
readClusterConfFromDisk();
}
@Override
public boolean interest(String context){
ains(context, DEFAULT_SEARCH_SEQ);
}
};
缺点:每⼀个Nacos节点都需要单独⼿动维护⼀个 f ⽂件,既增⼤了运维难度,⼜容易造成集群间成员节点列表数据的不⼀致性。
3. 地址服务器寻址英译中翻译
地址服务器寻址模式是 Nacos 官⽅推荐的⼀种集群成员节点信息管理,该模式利⽤了⼀个简易的 web 服务器,⽤于管理 f ⽂件的内容信息,这样,运维⼈员只需要管理这⼀份集群成员节点内容即可,⽽每个Nacos 成员节点,只需要向这个 web 节点定时请求当前最新的集群成员节点列表信息即可。
地址服务器寻址对应AddressServerMemberLookup类,查看核⼼的doStart⽅法。initAddressSys⽅法进⾏⼀些简单的初始化定
义,run⽅法为核⼼的逻辑。
public void doStart()throws NacosException {
this.maxFailCount = Integer.Property(HEALTH_CHECK_FAIL_COUNT_PROPERTY, DEFAULT_HEALTH_CHECK_FAIL_COUNT)); initAddressSys();
run();
}
查看run⽅法。在启动时需要执⾏同步成员节点的pull操作,也就是进⾏syncFromAddressUrl⽅法从地址服务器中获取节点列表,最多进⾏5次重试。并且创建⼀个5秒⼀次的定时任务AddressServerSyncTask,每五秒请求⼀次地址服务器。
private void run()throws NacosException {
// With the address rver, you need to perform a synchronous member node pull at startup
// Repeat three times, successfully jump out
boolean success =fal;
Throwable ex =null;
int maxRetry = Property(ADDRESS_SERVER_RETRY_PROPERTY, Integer.class, DEFAULT_SERVER_RETRY_TIME);
for(int i =0; i < maxRetry; i++){
try{
syncFromAddressUrl();
success =true;
break;
}catch(Throwable e){
ex = e;
("[rverlist] exception, error : {}", AllExceptionMsg(ex));
}
}
if(!success){
throw new NacosException(NacosException.SERVER_ERROR, ex);
}
GlobalExecutor.scheduleByCommon(new AddressServerSyncTask(), DEFAULT_SYNC_TASK_DELAY_MS);
}
查看定时任务AddressServerSyncTask,核⼼也是执⾏syncFromAddressUrl⽅法。
class AddressServerSyncTask implements Runnable {
@Override
public void run(){
if(shutdown){
return;
}
try{
syncFromAddressUrl();
}catch(Throwable ex){
addressServerFailCount++;
if(addressServerFailCount >= maxFailCount){
isAddressServerHealth =fal;
}
("[rverlist] exception, error : {}", AllExceptionMsg(ex));prent是什么意思
befriend}finally{
GlobalExecutor.scheduleByCommon(this, DEFAULT_SYNC_TASK_DELAY_MS);
}
}
}
查看核⼼的syncFromAddressUrl⽅法,该⽅法向地址服务器发送请求获取节点列表,然后调⽤afterLookup⽅法将节点列表存储到ServerMemberManager 中。
private void syncFromAddressUrl()throws Exception {
RestResult<String> result = restTemplate
.get(addressServerUrl, Header.EMPTY, Query.EMPTY, Type());
if(result.ok()){
isAddressServerHealth =true;
Reader reader =new Data());
try{
adServerConf(EnvUtil.analyzeClusterConf(reader)));
}catch(Throwable e){
("[rverlist] exception for analyzeClusterConf, error : {}",
}
addressServerFailCount =0;
}el{
addressServerFailCount++;
if(addressServerFailCount >= maxFailCount){
isAddressServerHealth =fal;
}whoisit
("[rverlist] failed to get rverlist, error code {}", Code());
}
}
afterLookup⽅法
不同的寻址模式都会调⽤afterLookup⽅法将节点信息存储到ServerMemberManager中,核⼼⽅法为ServerMemberManager类中的memberChange⽅法。