python操作redis的基础类

本文介绍了如何在项目中通过`IndexTool`类优雅地操作Redis,包括连接池管理、异常处理和不同环境配置。重点讲解了为何避免大value和大key存储,以及如何利用hash数据结构进行去重和设置过期时间。同时,通过示例展示了如何根据业务场景定制化工具类,如`OfflineIndexTool`和`QcmsPushTool`。
摘要由CSDN通过智能技术生成

项目中读取redis的类以及开发(测试)环境的处理**

import redis
from .config import Config 

class IndexTool(object):
    def __init__(self, host, port, pwd, db):
        self.ttl = 7*24*60*60
        self.pool = redis.ConnectionPool(
            host=host,
            port=port,
            password=pwd,
            db=db,
            decode_responses=True
        )
        self.debug = False

    def _get_conn(self):
        conn = redis.Redis(connection_pool=self.pool, decode_responses=True)
        return conn
        
    @retry.retry(3)
    def get(self, key, field):
        if self.debug:
            key = key + '@debug'
        conn = self._get_conn()
        val = conn.hget(key, field)
        return val
        
    @retry.retry(3)
    def get_all(self, key):
        if self.debug:
            key = key + '@debug'
        conn = self._get_conn()
        val = conn.hgetall(key)
        return val
        
    @retry.retry(3)
    def set(self, key, field, val):
        if self.debug:
            key = key + '@debug'
        conn = self._get_conn()
        ret = conn.hset(key, field, str(val))
        conn.hset(key, 'last_modify', str(time.time()))
        conn.expire(key, self.ttl)
        return ret
    
    @retry.retry(3)
    def hdel(self, key, field):
        if self.debug:
            key = key + '@debug'
        conn = self._get_conn()
        ret = conn.hdel(key, field)
        return ret
    
    @retry.retry(3)
    def set_str(self, key, val):
        if self.debug:
            key = key + '@debug'
        conn = self._get_conn()
        ret = conn.set(key, val)
        conn.expire(key, self.ttl)
        return ret

这里我们要注意以下几点:

1. redis不适合存放大value和大key,原因如下:
	1.内存不均:单value较大时,可能会导致节点之间的内存使用不均匀,间接地影响key的部分和负载不均匀;
    2.阻塞请求:redis为单线程,单value较大读写需要较长的处理时间,会阻塞后续的请求处理;
    3.阻塞网络:单value较大时会占用服务器网卡较多带宽,可能会影响该服务器上的其他Redis实例或者应用。
   因此hash数据结构的value不适合存放json

2. redis的hash数据结构不能单独为某个feild设置ttl,只能为key设置ttl
   redis的hash数据结构可以删除某个field,api为hdel(key, feild)

3. redis的hash数据结构尽可能的不要使用hgetall,因为许多redis的hash结构里会有update_time等相关字段,如果逻辑里没有处理掉这些key,极有可能程序会挂。

4. 根据业务经验,redis的key一般会选择md5规范后的字符串

一般来说我们在这个redis的工具类脚本里根据业务逻辑写一些业务工具类去继承redis的基类,比如说

class OfflineIndexTool(IndexTool):
    def __init__(self):
        conf = Config['offline.index.db']
        super(OfflineIndexTool, self).__init__(**conf)

    def set(self, key, field, val):
        raise RuntimeError('IndexReadOnly')

比如说我们有一个去重的功能

class QcmsPushTool(IndexTool):
    def __init__(self):
        conf = Config['qcms.push.db']
        super(QcmsPushTool, self).__init__(**conf)
        self.debug = Config["debug"]

    def delete_duplicate(self, key):
        res = self.get('conf_uniq', key)
        if not res:
            self.set('conf_uniq', key, str(time.time()))
            return None
        else:
            if int(time.time()) - int(float(res)) > 86400 * 7:
                self.hdel('conf_uniq', key)
                self.set('conf_uniq', key, str(time.time()))
                return None
            else:
                return res 

这段代码有点像LRU,如果key不在redis里或者当前时间超过redis中的存放时间一周,那么将其插入到redis中,返回None;如果key在redis中,那么返回redis中这条记录存放的时间。

目录结构

配置文件config.py 与redis基类同一级目录,config.py应该写成以下。

#!/usr/bin/env python
# encoding: utf-8
from utils.misc_tool import MiscTool

is_debug = True
if MiscTool.is_online():
    is_debug = False

Config = {
    'debug': is_debug,
    'hotnews.index.db': {
        'host': '10.175.162.16',
        'port': '26739',
        'db': 0,
        'pwd': '0296f0b83193cd46360'
    },
    'offline.index.db': {
        'host': '10.175.162.34',
        'port': '8648',
        'db': 0,
        'pwd': '3fe885fb4cec4dcd'
    },
    'qcms.push.db': {
        'host': '10.174.46.229',
        'port': '6264',
        'db': 0,
        'pwd': '716119d74f7c7c9d'
    },
    'tangshan.push.db': {
        'host': '10.174.46.229',
        'port': '6264',
        'db': 0,
        'pwd': '716119d74f7c7c9d'
    },
    'kuai.news.es': {
        'hosts': [{'host': '10.175.162.34', 'port': 18013}], 
        'timeout': 3600,
        'http_auth': 'hvpxs_w:e83330917f35f17af93588f39c08dfcc'
    }
}

我们这里的配置文件就是一个大字典(dict)

如何判断是否为线上环境

我们可以写一个基础类,获取当前是否是线上环境还是debug环境

#!/usr/bin/env python
# encoding: utf-8
import hashlib
import os


class MiscTool(object):
    @classmethod
    def make_md5(cls, input):
        md5_obj = hashlib.md5()
        md5_obj.update(input.encode())
        md5_str = md5_obj.hexdigest()
        return md5_str
    
    @classmethod
    def is_online(cls):
        ret = False
        env = os.environ.get('ONLINE')
        if env == 'true':
            ret = True
        return ret

我们可以通过启动程序的shell脚本来控制当前是debug模式还是线上模式

export ONLINE="true"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值