title: Python redis 使用介绍subtitle: redis初探
date: 2021-03-27
author: NSX
catalog: true
tags:
- redis

Redis 简介

REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

Redis 优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

    安装 redis 模块

Python 要使用 redis,需要先安装 redis 模块:

  1. sudo pip3 install redis
  2. sudo python setup.py install

测试是否安装成功:

  1. >>> import redis
  2. >>> r = redis.StrictRedis(host='localhost', port=6379, db=0)
  3. >>> r.set('foo', 'bar')
  4. True
  5. >>> r.get('foo')
  6. 'bar'

redis 提供两个类 Redis 和 StrictRedis, StrictRedis 用于实现大部分官方的命令,Redis 是 StrictRedis 的子类,用于向后兼用旧版本。

redis 取出的结果默认是字节,我们可以设定 decode_responses=True 改成字符串。

实例

  1. import redis # 导入redis 模块
  2. r = redis.Redis(host='localhost', port=6379, decode_responses=True)
  3. r.set('name', 'runoob') # 设置 name 对应的值
  4. print(r['name'])
  5. print(r.get('name')) # 取出键 name 对应的值
  6. print(type(r.get('name'))) # 查看类型

输出结果为:

  1. runoob
  2. runoob
  3. <class 'str'>

连接redis sentinel集群

https://blog.csdn.net/u012887259/article/details/102425691

示例代码

  1. # import redis
  2. from redis.sentinel import Sentinel
  3. """
  4. 1、通过访问Sentinel服务的方式,获取redis的master、slave节点信息
  5. 2、向master redis写入数据
  6. 3、从slave redis读取数据
  7. """
  8. # 连接哨兵服务器(主机名也可以用域名)
  9. sentinel = Sentinel([('192.168.196.129', 26379),
  10. ('192.168.196.132', 26379)
  11. ],
  12. socket_timeout=0.5)
  13. # 获取主服务器地址
  14. master = sentinel.discover_master('mymaster')
  15. print(master)
  16. # 输出:('192.168.196.132', 6379)
  17. # 获取从服务器地址
  18. slave = sentinel.discover_slaves('mymaster')
  19. print(slave)
  20. # 输出:[('192.168.196.129', 6379)]
  21. # 获取主服务器进行写入
  22. master = sentinel.master_for('mymaster', socket_timeout=0.5, password='newpwd', db=0)
  23. w_ret = master.set('foo', 'bar')
  24. # 输出:True
  25. # 获取从服务器进行读取(默认是round-roubin,随机从多个slave服务中读取数据)
  26. slave = sentinel.slave_for('mymaster', socket_timeout=0.5, password='newpwd', db=0)
  27. r_ret = slave.get('foo')
  28. print(r_ret)
  29. # 输出:bar

封装工具类方法

  1. from redis.sentinel import Sentinel
  2. class redisSentinelHelper():
  3. def __init__(self,sentinel_list,service_name,password,db):
  4. self.sentinel = Sentinel(sentinel_list,socket_timeout=0.5)
  5. self.service_name = service_name
  6. self.password = password
  7. self.db = db
  8. def get_master_redis(self):
  9. return self.sentinel.discover_master(self.service_name)
  10. def get_slave_redis(self):
  11. return self.sentinel.discover_slaves(self.service_name)
  12. def set_key(self,key,value):
  13. master = self.sentinel.master_for(
  14. service_name=self.service_name,
  15. socket_timeout=0.5,
  16. password=self.password,
  17. db=self.db
  18. )
  19. return master.set(key,value)
  20. def get_key(self,key):
  21. slave = self.sentinel.slave_for(
  22. service_name=self.service_name,
  23. socket_timeout=0.5,
  24. password=self.password,
  25. db=self.db
  26. )
  27. return slave.get(key)
  28. def _test():
  29. # redis info
  30. sentinel_list = [('192.168.196.129', 26379),('192.168.196.132', 26379)]
  31. password = 'newpwd'
  32. db = 0
  33. service_name = 'mymaster'
  34. # create redis link
  35. rsh = redisSentinelHelper(sentinel_list=sentinel_list,password=password,service_name=service_name,db=db)
  36. # test set key : key1 test-insert-key1
  37. rsh.set_key('key1','test-insert-key1')
  38. # get key1
  39. print(rsh.get_key('key1'))
  40. if __name__ == '__main__':
  41. _test()

运行如下:

  1. D:\Python37\python3.exe D:/pythonProject/redis-test/test7.py
  2. b'test-insert-key1'

其中,我没有把设置master节点写在初始化,而是在set key操作的时候才创建连接,主要是后续想要测试master节点变化的情况下,写入能够继续。

当然这样的话性能肯定不会很好,有很多可以根据实际情况修改的地方。

测试:当master节点切换,能否自动连续写入

当然,在sentinel执行master切点切换的过程,肯定会有些丢失,但是主要是要看切换之后,是否可以自动继续写入数据。

首先编写一个循环写入的示例

  1. from redis.sentinel import Sentinel
  2. class redisSentinelHelper():
  3. def __init__(self,sentinel_list,service_name,password,db):
  4. self.sentinel = Sentinel(sentinel_list,socket_timeout=0.5)
  5. self.service_name = service_name
  6. self.password = password
  7. self.db = db
  8. def get_master_redis(self):
  9. return self.sentinel.discover_master(self.service_name)
  10. def get_slave_redis(self):
  11. return self.sentinel.discover_slaves(self.service_name)
  12. def set_key(self,key,value):
  13. master = self.sentinel.master_for(
  14. service_name=self.service_name,
  15. socket_timeout=0.5,
  16. password=self.password,
  17. db=self.db
  18. )
  19. return master.set(key,value)
  20. def get_key(self,key):
  21. slave = self.sentinel.slave_for(
  22. service_name=self.service_name,
  23. socket_timeout=0.5,
  24. password=self.password,
  25. db=self.db
  26. )
  27. return slave.get(key)
  28. def _test():
  29. # redis info
  30. sentinel_list = [('192.168.196.129', 26379),('192.168.196.132', 26379)]
  31. password = 'newpwd'
  32. db = 0
  33. service_name = 'mymaster'
  34. # create redis link
  35. rsh = redisSentinelHelper(sentinel_list=sentinel_list,password=password,service_name=service_name,db=db)
  36. # test set key : key1 test-insert-key1
  37. # rsh.set_key('key1','test-insert-key1')
  38. # get key1
  39. # print(rsh.get_key('key1'))
  40. # loop set key
  41. for i in range(0,1000000):
  42. rsh.set_key('key' + str(i), i)
  43. print(rsh.get_key('key' + str(i)))
  44. if __name__ == '__main__':
  45. _test()