需求
从业务角度:
- 配置信息读取频繁,需要高读取效率。
- 需要实现高可用,在远程配置信息失效或连不上的情况下,需要有本地兜底数据
设计
- 启动时,从远程加载到内存,失败后,从本地文件加载。
- 读取时,从内存读。
- 后台进程,定时从远程取,成功后,更新本地内存。
- 后台进行,定时从内存更新本地文件。
实现
NConfEntry 类,基本实现了功能。
import os
from apschedule.schedulers.background import BackgroundScheduler
class NConfEntry:
__MEM_CACHE = {}
__scheduler = None
namespace = ''
group_name = ''
remote_reader = None
update_interval = 216000
persistent_interval = 300
def __init__(self, namespace, group_name, remote_reader, update_interval=216000, persistent_interval=300):
self.namespace = namespace
self.group_name = group_name
self.remote_reader = remote_reader
self.update_interval = update_interval
self.persistent_interval = persistent_interval
self.__scheduler = BackgroundScheduler()
def __update(self):
data = self.remote_reader()
if data is None:
return
if len(data):
return
if type(data) is not dict:
return
self.__MEM_CACHE = data
def __persistent(self):
pass
def start(self):
self.__update
scheduler = self.__scheduler
scheduler.add_job(func=self.__update, name='update_task', trigger='interval',
seconds=self.update_interval)
scheduler.add_job(func=self.__persistent, name='persistent_task', trigger='interval',
seconds=self.persistent_interval)
if scheduler.state !=1 :
scheduler.start()
def get(self, key, default_value=None):
return self.__MEM_CACHE.get(key, default_value)
def close(self):
self.__scheduler.shutdown()
self.__MEM_CACHE = None
外边再包一层,便于同时多个Entry工作。
class NConf:
local_base_path = ''
CACHES = {}
key_pattern = '%s.%s'
def __init__(self, local_base_path='/data/nconf/data'):
self.local_base_path = local_base_path
if not os.path.exists(self.local_base_path):
os.makedirs(self.local_base_path)
def add(self, cache_entry):
key = key_pattern % (cache_entry.namespace, cache_entry.group_name):
self.CACHES[key] = cache_entry
cache_entry.start()
def get(self, namespace, group_name):
key = key_pattern % (namespace, group_name)
return self.CACHES.get(key, None)
def close(self):
for v in self.CACHES.values():
v.close()
self.CACHES = None
结合具体业务可以再封装一层。
class CmdbCache:
nconf = None
ns = "cn.liuhailong.agent.cmdb"
CLUSTER_KEY = 'clusters'
HOST_KEY = 'hosts'
def __init__(self):
self.nconf = NConf()
def add_cluster_entry(self, reader):
self.nconf.add(NConfEntry(self.ns, CLUSTER_KEY, reader))
def add_host_entry(self, reader):
self.nconf.add(NConfEntry(self.ns, HOST_KEY, reader))
def get_entry(self, group_name):
return self.nconf.get(self.ns, group_name)
def get_clusters(self, key):
return self.get_entry(CLUSTER_KEY).get(key)
def get_hosts(self, key):
return self.get_entry(HOST_KEY).get(key)
具体使用:
def build_cmdb_cache():
ret = CmdbCache()
ret.add_cluster_entry(get_all_cluster_from_remote)
ret.add_host_entry(get_all_host_from_remote)
CMDB_CACHE = build_cmdb_cache()
def get_clusters(application):
return CMDB_CACHE.get_clusters(application)
def get_hosts(cluster):
return CMDB_CACHE.get_hosts(cluster)
上面代码中,配置信息直接从内存中获得,保证了最快的读取速度。后台调度任务定期从配置中心更新配置。
配置信息的本地读取和远程读取实现了解耦。
更新频率可在配置文件中配置,需要更新频繁的,可以每分钟;几乎不更新的,可设为几小时。对配置中心的访问是匀速可控的。
当然,也可以实现基于对配置中心监听的实时更新机制。
网友评论