redis 学习 - 存储配置信息
本篇已收录至redis in action 学习笔记系列
将系统中的所有程序的配置信息都存储到 redis 当中, 需要获取的时候直接从 redis 中获取, 是否是一个好注意呢?
情景设计
公司的系统由于发版, 需要暂时停止服务一段时间, 这段时间如果有用户访问系统, 则需要得到一个
系统正在维护
的消息. 并且当用户不耐其烦的疯狂刷新系统 UI, 尝试访问时, 系统应该对此情况予以考虑设计应对的情况.
在 redis server中存储一个key为表示系统是否正在维护, 当用户请求系统资源时, 会通过此函数的返回值判断系统当前状态. 并且加了一个 1秒 的请求限制.
在分布式系统架构中将配置信息放到一个共享访问的地方的威力
建立一个 redis server 作为配置信息 server?
设计一个set config
函数:
def set_config(conn, type, component, config):
conn.set(
'config:%s:%s'%(type, component),
json.dumps(config))
还有 get config
:
使用python的装饰器设计一个自动连接redis server管理机制
上面的code里面无论是 set_config 还是 get_config, 参数都有一个 conn. 这就意味着调用 xx_config 的调用者必须先将对应的 server 连接上得到一个 conn.
redis自动连接装饰器:
REDIS_CONNECTIONS = {}
def redis_connection(component, wait=1):
key = 'config:redis:' + component
def wrapper(function):
def call(*args, **kwargs):
old_config = CONFIGS.get(key, object())
config = get_config(
config_connection, 'redis', component, wait)
if config != old_config:
REDIS_CONNECTIONS[key] = redis.Redis(**config)
return function(
REDIS_CONNECTIONS.get(key), *args, **kwargs)
return call
return wrapper
代码解析:
- 有个函数叫
redis_connection
- 参数
component
, type 应为 string, 会通过它拼接出 key 值. - 定义了一个内部嵌套函数,
wrapper
, 参数为function
, 跳过. return wrapper
, redis_connection 的返回值是 需要执行 wrapper 函数, 得到 wrapper 函数的返回值返回.- 进入
wrapper
- 定义了一个内部嵌套函数,
call
, 参数为默认参数形式,*args, **kwargs
, 继续跳过 - return
call
, 此处调用call
, 并将其返回值返回. - 进入
call
- 获取旧的config 连接串, 获取新的config连接串, 旧的和新的对比, 如果不相等, 则更新 REDIS_CONNECTIONS 中的值
- 否则执行
function(REDIS_CONNECTIONS.get(key), *args, **kwargs)
, function 是一个函数, 第一个参数是 REDIS_CONNECTIONS.get(key) 即 conn, 后面的参数爱是啥是啥 - call 的返回值是 function 执行过后的返回值
- wrapper 的返回值是 call 返回的值
- redis_connection 的返回值是 wrapper 的返回值
- 解析完毕.
举例使用:
@redis_connection('logs') #A
def log_recent(conn, name, message, severity=logging.INFO, pipe=None):
severity = str(SEVERITY.get(severity, severity)).lower() #B
destination = 'recent:%s:%s'%(name, severity) #C
message = time.asctime() + ' ' + message #D
pipe = pipe or conn.pipeline() #E
pipe.lpush(destination, message) #F
pipe.ltrim(destination, 0, 99) #G
pipe.execute() #H
log_recent('main', 'User 235 logged in') #C
装饰器的优点在于调用方法的使用者不必考虑连接 server 的问题.