也不知道咋回事,怎么坑这么多。
问题现象:一个程序获取拎一个服务的缓存时,数据格式报错。
找了很久,发现是Dogpile的问题:数据还在,但是结构变了。如原来缓存的是{'a': 111, 'b_list':[1,2,3]}
,再次获取缓存时结果是[1,2,3]
我已经懒得再去找为什么了,反正用的是set和get,我不知道为什么这样。哪怕是报错也好呀…
其实这样的工具我早就自己做了…
import pandas as pd
from redis import Redis, ConnectionPool
import json
import pickleclass LittleRQ:algo_ver='1000.004'def __init__(self, host = None, port = 24008, decode_responses=True,password=None, db=1, smethod = 'json'):"""初始化LittleRQ对象。Args:host (str): Redis服务器主机名或IP地址。port (int): Redis服务器端口号。decode_responses (bool, optional): 是否解码存储在Redis中的数据。默认为True。password (str, optional): 连接Redis服务器的密码。默认为None。db (int, optional): Redis数据库索引。默认为0。"""self.host = host self.port = portself.db = db self.decode_responses = decode_responsesself.password= passwordself.smethod = smethodself.pool = ConnectionPool(host=self.host, port=int(self.port), decode_responses=self.decode_responses, password=self.password, db=self.db)self.conn = Redis(connection_pool=self.pool)def info(self, is_full_info=False):"""获取Redis服务器的一些重要信息。Args:is_full_info (bool, optional): 是否返回完整的服务器信息。默认为False。Returns:dict: 包含服务器信息的字典。"""info_dict = self.conn.info()if is_full_info:return info_dictres_dict = {}the_db_name = 'db'+str(self.db)need_keys = [the_db_name,'cluster_enabled','role','total_system_memory_human','used_memory_peak_human','used_memory_human','connected_clients']for k in need_keys:res_dict[k] = info_dict[k]return res_dictdef dbsize(self):"""返回当前数据库中键的数量。Returns:int: 键的数量。"""return self.conn.dbsize()def list_keys(self, is_force=False):"""返回当前数据库中的键列表。Args:is_force (bool, optional): 是否强制返回键列表。默认为False。Returns:list: 键列表。"""cur_len = self.dbsize()if cur_len >=1000 and is_force is False:print('键值列表长度 %s 超过一千,请用is_force允许查询' % cur_len )return Falsereturn self.conn.keys()def set_value(self, key=None, value=None, set_type=None, ex_seconds=None, ex_miliseconds=None):"""设置键值对。Args:key (str): 键名。value (str): 键值。set_type (str, optional): 设置类型,可以是'ex'(已存在)或'nx'(不存在)。默认为None,表示覆盖。ex_seconds (int, optional): 键的过期时间(秒)。默认为None。ex_miliseconds (int, optional): 键的过期时间(毫秒)。默认为None。is_json (bool, optional): 是否将值转换为JSON格式。默认为True。Returns:bool: 设置成功返回True,否则返回False。"""if self.smethod == 'json':value = json.dumps(value)else:value = pickle.dumps(value)assert set_type in ['ex','nx',None], 'set操作允许对ex已存在或者nx不存在操作。默认None覆盖。'if set_type:if set_type =='ex':res = self.conn.set(key, value, ex=ex_seconds, px=ex_miliseconds, xx=True)else:res = self.conn.set(key, value, ex=ex_seconds, px=ex_miliseconds, nx=True)else:res = self.conn.set(key, value, ex=ex_seconds, px=ex_miliseconds)return res def get_value(self, key=None):"""获取键的值。Args:key (str): 键名。Returns:str: 键的值。"""value = self.conn.get(key)if value:try:if self.smethod == 'json':return json.loads(value)else:return pickle.loads(value)except:return value else:return value def increment(self, key=None, num=1):"""对键的值进行自增操作。Args:key (str): 键名。num (int, optional): 自增数。默认为1。Returns:int: 自增后的值。"""return self.conn.incr(key, num)def decrement(self, key=None, num=1):"""对键的值进行自减操作。Args:key (str): 键名。num (int, optional): 自减数。默认为1。Returns:int: 自减后的值。"""return self.conn.decr(key, num)def delete_key(self, key=None):"""删除键。Args:key (str): 键名或键列表。Returns:int: 被删除键的数量。"""assert isinstance(key, str) or isinstance(key, list),'字符或者列表'if isinstance(key, str):key = [key]return self.conn.delete(*key)def expire_key(self, key=None, ex_seconds=1):"""设置键的过期时间。Args:key (str): 键名。ex_seconds (int): 过期时间(秒)。Returns:bool: 设置成功返回True,否则返回False。"""return self.conn.expire(key, ex_seconds)
只要再加一个命名工具就好
from typing import List, Optional
from pydantic import BaseModelclass TName(BaseModel):space : str tier1 : str tier2 : str @propertydef prefix(self):return '.'.join([self.space, self.tier1,self.tier2]) + '.'
使用例子
redis_ip = 'IP'
passwd = 'YOURS'
tname = TName(space='andypile', tier1 ='tier1', tier2 = 'tier2')
varname = tname.prefix + 'varname'
lq = LittleRQ(host = redis_ip, port = 24008, decode_responses=True,password=passwd, db=1)
# 设置一个缓存
some_dict ={'a':111, 'b':[1,2,3]}
lq.set_value(key=varname, value=some_dict)lq.get_value(key=varname)In [11]: lq.get_value(key=varname)
Out[11]: {'a': 111, 'b': [1, 2, 3]}In [12]: varname
Out[12]: 'andypile.tier1.tier2.varname
可以在set_value时指定超时时间,也可以在之后设置expire时间。然后还可以进行增量计数,这些都是redis最常用的功能。再也不用dogpile了,实在很坑。