python连接redis的几种方式、原理剖析

0、 安装驱动

pip install redis
pip install python-redis

1、 直接连接

redis-py提供 两个类Redis和StrictRedi s 用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
redis取出的结果默认是字节,可以使用 decode_responses=True  改成字符串。
import redis

r = redis.Redis(host='127.0.0.1', port=6379, password="123", decode_responses=True, max_connections=None)

r.set('foo', 'Bar')
print(r.get('foo')) 

''' 
decode_responses=False: b'Bar' 
decode_responses=True:    Bar 
''' 

注:连接redis,加上decode_responses=True,则写入键值对中的valuestr类型,不加这个参数写入的则为字节类型

 

2、 连接池--适用于并发量高场景

redis-py 使用connection pool 来管理对一个redis server的所有连接, 避免每次建立、释放连接的开销 默认,每个Redis实例都会维护一个自己的连接池 可以直接建立一个连接池,然后作为参数Redis, 这样就可以实现多个Redis实例共享一个连接池。
import redis

kwargs = {
    'host': '127.0.0.1',
    'port': 6379,
    'decode_responses': True,
    'retry_on_timeout': 3,
    'max_connections': 1024  # 默认2^31
}

pool = redis.ConnectionPool(**kwargs) 
r = redis.Redis(connection_pool=pool)

或者:
pool = redis.ConnectionPool(decode_responses=True)                   # 建立连接池
r = redis.Redis(connection_pool=pool,host='127.0.0.1', port=6379)   # 从连接池获取连接

r.set('book', '西游记')
print(r.get('book'))    # 西游记

2.1、为什么使用连接池?

Redis是数据库,C/S模式(C/S本身是种远程通信的交互模式),使用它需要建立连接。客户端访问Redis服务器到返回数据给客户端(一次数据请求), 耗时主要花费在两处:
    1、底层的网络通信,因为每次数据交互需先建立连接;
    2、Redis数据库处理
前期的底层网络通信占用时长比较多,而连接池可以实现在客户端建立多个连接并且不释放,当需要连接的时候直接从池子获取已经建立的连接,使用完则还给连接池,这免去了数据库连接所占用的时长。
 
 

2.2、连接池原理剖析

1、当redis.ConnectionPool 实例化的时候, 做了什么
这个 连接池的实例化其实未做任何真实的redis连接, 仅仅是设置最大连接数, 连接参数和连接类
python连接redis的几种方式、原理剖析_第1张图片
 
 
2、 redis . Redis ( connection_pool = pool ) 实例化的时候,,又做了什么
python连接redis的几种方式、原理剖析_第2张图片

可以看出,使用redis.Redis() 即使不创建连接池, 也会自己创建。到这里, 我们还没有看到什么redis连接真实发生。

3、r.set('book', '西游记'),set操作,这个时候一定会发生redis连接

python连接redis的几种方式、原理剖析_第3张图片

 继续看看execute_command:
python连接redis的几种方式、原理剖析_第4张图片
 
连接创建,调用的是ConnectionPool的get_connection:pool.get_connection(command_name, **options)
python连接redis的几种方式、原理剖析_第5张图片
 
连接池有可用的连接则直接从连接池获取一个( connection = self ._available_connections.pop()),否则创建一个连接( connection = self .make_connection()):
python连接redis的几种方式、原理剖析_第6张图片
 
 
释放连接:pool.release(conn)
连接池对象调用release方法, 将连接从_in_use_connections 放回 _available_connections, 这样后续的连接获取就能再次使用这个连接了。
python连接redis的几种方式、原理剖析_第7张图片
 
 
 

2.3、redis连接的单例实现  

# coding:utf-8
import redis

class RedisDBConfig:
    HOST = '127.0.0.1'
    PORT = 6379
    DBID = 0

def operator_status(func):
    """get operatoration status
    """
    def gen_status(*args, **kwargs):
        error, result = None, None
        try:
            result = func(*args, **kwargs)
        except Exception as e:
            error = str(e)
           
        return {'result': result, 'error': error}
    return gen_status


class RedisModel(object):
    def __init__(self):
        if not hasattr(RedisModel, 'pool'):
            RedisModel.create_pool()
        self._connection = redis.Redis(connection_pool=RedisModel.pool)

    # python中,所有类的实例中的成员变量,都是公用一个内存地址,因此,及时实例化多个RedisCache类,内存中存在的pool也只有一个
    @staticmethod
    def create_pool():
        RedisModel.pool = redis.ConnectionPool(
            host=RedisDBConfig.HOST,
            port=RedisDBConfig.PORT,
            db=RedisDBConfig.DBID)

    @operator_status
    def set_data(self, key, value):
        """set data with (key, value)
        """
        return self._connection.set(key, value)

    @operator_status
    def get_data(self, key):
        """get data by key
        """
        return self._connection.get(key)

    @operator_status
    def del_data(self, key):
        """delete cache by key
        """
        return self._connection.delete(key)

def f1():
    r = RedisModel()
    print(id(r))       # 3118437616384

def f2():
    r1 = RedisModel()  # 3118437616384
    print(id(r1))


if __name__ == '__main__':
    print(RedisModel().set_data('Testkey', "Simple Test"))   # {'result': True, 'error': None}
    print(RedisModel().get_data('Testkey'))                  # {'result': b'Simple Test', 'error': None}
    print(RedisModel().del_data('Testkey'))                  # {'result': 1, 'error': None}
    print(RedisModel().get_data('Testkey'))                  # {'result': None, 'error': None}
    f1()
    f2()

 

3、参考:

https://blog.csdn.net/dcba2014/article/details/99292430          python redis之连接池的原理
https://blog.csdn.net/moxiaomomo/article/details/27085415  【python】使用redis pool的一种单例实现方式

 

 

 

 

 
 

你可能感兴趣的:(redis,redis,连接池)