一、实现一个轻量级简单的配置中心,同时不考虑使用zk?
1.由于我们使用的配置中心需要兼容多套环境,因此需要多环境
2.需要有权限控制
3.需要对配置的信息,能够实时响应
4.如果配置信息存储在数据库,为了减轻数据库的压力,可以进行持久化到磁盘文件中
当时这里会有一个问题需要考虑,如果持久化到磁盘,需要考虑如果配置发生了改变,需要能够实时同步到磁盘文件中,因此此时需要考虑一个线程进行实时同步。
5.对应配置信息发生增、删、改,能够实时更新和修改
二、xxl-conf的官方架构图
从图中,我们可以看到配置中心如果执行了配置操作,此时会做一个写的操作到文件,其会做一个广播、同步的操作,同步镜像文件,执行配置的刷新操作。在调用的时候,能够实时拉取到最新的配置信息。这里做了两个持久化,一个是持久化到了数据库,一个是持久化到文件。在之前的版本,xxl-conf使用过zookeeper作为存储配置的作为配置中心。
三、xxl-conf的使用
一个是服务端,一个是客户端。服务端提供了一个可视化的界面,我们可以在可视化界面中,执行配置信息的增、删、查、改。同时接入的业务系统需要引入xxl-conf-core。
服务端,我们可以看到配置管理中的key-value的对应信息,同时描述信息。
客户端:引入xxl-conf-core的依赖即可。
配置配置信息:
xxl.conf.admin.address=http://localhost:8080/
xxl.conf.env=test
xxl.conf.access.token=
xxl.conf.mirrorfile=/data/applogs/xxl-conf/xxl-conf-mirror-sample.properties
可以看到主要是服务端的请求地址、对应的配置环境、token、镜像文件存放的路径。
如果配置成功后,可以运行接入的业务系统的例子,可以看到文件路径中会有启动的服务端和业务系统的日志信息,同时还有配置文件的配置信息
可以看到配置配置数据信息在信息配置后,持久化到了磁盘文件中。
此时可以看到运行获取配置的效果:
可以看到获取到了对应的key和value的值。
四、表结构
可以看到xxl-conf中有三张表是值得我们关注的,一张是xxl_conf_node,一张是xxl_conf_node_msg。从ConfController的增、删、改种可以看到,在做配置信息的变更后,同时会sendConfMsg的动作,此时xxl_conf_node_msg中会存在数据。另外一张表是一张审计日志表,方便查看谁对配置做了修改。
xxl_conf_env是对应环境的信息。xxl_conf_user是用户信息。xxl_conf_project是对应的项目的名称信息。
五、原理
在启动服务端的时候,由于XxlConfNodeServiceImpl实现了InitializingBean, DisposableBean接口,因此会做线程启动。
可以看到主要的代码:
查配置消息表信息
遍历配置消息,进行文件同步
同步完成后,执行老配置消息清理
// new message, filter readed
List<XxlConfNodeMsg>messageList=xxlConfNodeMsgDao.findMsg(readedMessageIds);
if (messageList!=null&&messageList.size()>0) {
for (XxlConfNodeMsgmessage: messageList) {
readedMessageIds.add(message.getId());
// sync file 同步文件
setFileConfData(message.getEnv(), message.getKey(), message.getValue());
}
}
// clean old message; 清理老消息
if ( (System.currentTimeMillis()/1000) %confBeatTime==0) {
xxlConfNodeMsgDao.cleanMessage(confBeatTime);
readedMessageIds.clear();
}
找到记录消息的xxl_conf_node_msg,如果存在,则需要做文件同步处理,同时清理调老的消息。
启动客户端,可以看到会做初始化操作:
三个初始化,初始化完成后,做监听操作。首先对远程的配置信息进行初始化,然后初始化镜像文件,初始化缓存信息和线程,循环刷新和监控。完成后监听所有的key发生改变的时候,做刷新操作。
/**
* init 初始化
*
* @param adminAddress
* @param env
*/
publicstaticvoidinit(StringadminAddress, Stringenv, StringaccessToken, Stringmirrorfile) {
// init
// init remote util 初始化远程配置
XxlConfRemoteConf.init(adminAddress, env, accessToken);
// init mirror util
XxlConfMirrorConf.init(mirrorfile);
// init cache + thread, cycle refresh + monitor
XxlConfLocalCacheConf.init();
// listener all key change
XxlConfListenerFactory.addListener(null, newBeanRefreshXxlConfListener());
}
此时也会启动线程操作:
只不过此时获取的所有的配置信息
//获取所有配置的节点列表,这里是拿到所有信息的关键方法
List<XxlConfNode>confNodeList=xxlConfNodeDao.pageList(offset, pagesize, null, null, null);
while (confNodeList!=null&&confNodeList.size()>0) {
for (XxlConfNodeconfNoteItem: confNodeList) {
// sync file 同步文件
StringconfDataFile=setFileConfData(confNoteItem.getEnv(), confNoteItem.getKey(), confNoteItem.getValue());
// collect confDataFile
confDataFileList.add(confDataFile);
}
offset+=1000;
confNodeList=xxlConfNodeDao.pageList(offset, pagesize, null, null, null);
}
// clean old registry-data file 清理老的配置文件
cleanFileConfData(confDataFileList);
获取节点配置信息,如果不为空,则同步对应节点的配置信息,然后清理老的配置文件。这里做了1个1000以上,做多次查询。
然后可以看到变更执行的监听:
XxlConfClient.addListener("default.key01", (key, value) ->logger.info("配置变更事件通知:{}={}", key, value));
总体来说,xxl-conf的作者比较贴心,很容易上手xxl-conf。