Nacos1.4.2源码<二>服务端配置

一、配置储存

从整体上Nacos服务端的配置存储分为三层:

  • 内存:Nacos每个节点都在内存里缓存了配置,但是只包含配置的md5(缓存配置文件太多了),所以内存级别的配置只能用于比较配置是否发生了变更,只用于客户端长轮询配置等场景。
  • 文件系统:文件系统配置来源于数据库写入的配置。如果是集群启动或mysql单机启动,服务端会以本地文件系统的配置响应客户端查询。
  • 数据库:所有写数据都会先写入数据库。只有当以derby数据源(-DembeddedStorage=true)单机(-Dnacos.standalone=true)启动时,客户端的查询配置请求会实时查询derby数据库。

1.1.内存

对于写请求,Nacos会将数据先更新到数据库,之后异步写入所有节点的文件系统并更新内存。

CacheItem在Nacos服务端对应一个配置文件,缓存了配置的md5,持有一把读写锁控制访问冲突。

public class CacheItem {
    // groupKey = namespace + group + dataId
    final String groupKey;
    // 配置md5
    public volatile String md5 = Constants.NULL;
    // 更新时间
    public volatile long lastModifiedTs;
    // nacos自己实现的简版读写锁
    public SimpleReadWriteLock rwLock = new SimpleReadWriteLock();
    // 配置文件类型:text/properties/yaml
    public String type;
    // ... 省略其他betaIp和tag相关属性
}

ConfigCacheService一个重要的服务,负责管理所有内存配置CacheItem。

public class ConfigCacheService {
		// 持久层服务(Derby或MySQL)
    private static PersistService persistService;
    // groupKey -> cacheItem.
    private static final ConcurrentHashMap<String, CacheItem> CACHE = new ConcurrentHashMap<String, CacheItem>();
  
    // 更新配置的md5
    public static void updateMd5(String groupKey, String md5, long lastModifiedTs) {
        CacheItem cache = makeSure(groupKey);
        if (cache.md5 == null || !cache.md5.equals(md5)) {
            cache.md5 = md5;
            cache.lastModifiedTs = lastModifiedTs;
            NotifyCenter.publishEvent(new LocalDataChangeEvent(groupKey));
        }
    }
    // 比较入参md5与缓存md5是否一致
    public static boolean isUptodate(String groupKey, String md5, String ip, String tag) {
        String serverMd5 = ConfigCacheService.getContentMd5(groupKey, ip, tag);
        return StringUtils.equals(md5, serverMd5);
    }
    // 获取缓存配置
    public static CacheItem getContentCache(String groupKey) {
        return CACHE.get(groupKey);
    }
    // 创建配置
    static CacheItem makeSure(final String groupKey) {
        CacheItem item = CACHE.get(groupKey);
        if (null != item) {
            return item;
        }
        CacheItem tmp = new CacheItem(groupKey);
        item = CACHE.putIfAbsent(groupKey, tmp);
        return (null == item) ? tmp : item;
    }
    // 获取配置读锁
    public static int tryReadLock(String groupKey) {
        CacheItem groupItem = CACHE.get(groupKey);
        int result = (null == groupItem) ? 0 : (groupItem.rwLock.tryReadLock() ? 1 : -1);
        return result;
    }
    // 释放配置读锁
    public static void releaseReadLock(String groupKey) {
        CacheItem item = CACHE.get(groupKey);
        if (null != item) {
            item.rwLock.releaseReadLock();
        }
    }
}

1.2文件系统

Nacos刚启动时,内存中与文件系统中未必存在所有配置,所以DumpService会全量dump配置到文件系统与内存中。 另外当数据库配置发生变化时,也会dump到本地文件系统。

// 启动时DumpService全量dump
protected void dumpOperate(DumpProcessor processor, DumpAllProcessor dumpAllProcessor,
        DumpAllBetaProcessor dumpAllBetaProcessor, DumpAllTagProcessor dumpAllTagProcessor) throws NacosException {
    // 构造各类runnable任务...

    // 首次启动,dump数据库中所有配置到文件系统和内存中
    dumpConfigInfo(dumpAllProcessor);
    // 非单机部署,提交dump任务
    if (!EnvUtil.getStandaloneMode()) {
      ConfigExecutor.scheduleConfigTask(heartbeat, 0, 10, TimeUnit.SECONDS);
      // dump all config
      ConfigExecutor.scheduleConfigTask(dumpAll, initialDelay, DUMP_ALL_INTERVAL_IN_MINUTE, TimeUnit.MINUTES);
      // dump beta config
      ConfigExecutor
        .scheduleConfigTask(dumpAllBeta, initialDelay, DUMP_ALL_INTERVAL_IN_MINUTE, TimeUnit.MINUTES);
      // dump tag config
      ConfigExecutor
        .scheduleConfigTask(dumpAllTag, initialDelay, DUMP_ALL_INTERVAL_IN_MINUTE, TimeUnit.MINUTES);
    }
    ConfigExecutor.scheduleConfigTask(clearConfigHistory, 10, 10, TimeUnit.MINUTES);
}

1.3数据库

配置文件主要存储在config_info表中。Nacos有三个配置项与数据源的选择有关:

  • application.properties中的spring.datasource.platform配置项,默认为空,可以配置为mysql
  • -Dnacos.standalone,true代表单机启动,false代表集群启动,默认false
  • -DembeddedStorage,true代表使用嵌入式存储derby数据源,false代表不使用derby数据源,默认false

这块感觉比较乱,通过伪代码的方式理一下。主要是spring.datasource.platform在默认为空的场景下,满足条件集群启动且-DembeddedStorage=false(默认false),还是会选择mysql数据源。也就是说,集群启动,如果没特殊配置,Nacos会使用MySQL数据源。

// 指定数据源为mysql,直接返回mysql
if (mysql) {
	return mysql;
}
// 如果单机部署,没指定数据源,使用derby
if (standalone) {
	return derby;
} else {
    // 如果集群部署且指定使用嵌入式存储,使用derby
	if (embeddedStorage) {
		return derby;
	} else {
	    // 集群部署,默认使用mysql存储
		return mysql;
	}
}

二、配置查询

GET /v1/cs/configs接口负责配置查询。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值