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 的问题.

posted @ 2020-03-28 20:40  YanyuWu  阅读(543)  评论(0编辑  收藏  举报