Redis是彻底开源免费的,遵照BSD协议,是一个高性能的key-value数据库(非关系型数据库)。html
本质:将数据保存在内存中。python
用途:缓存、消息队列。redis
Redis支持五种数据类型:字符串、列表、哈希散列表、集合、有序集合。和Memcached相似,但它支持存储的values类型相对更多。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操做,并且这些操做都是原子性的。在此基础上,redis支持各类不一样方式的排序。数据库
Redis支持数据的持久化,能够将内存中的数据保存在磁盘中,重启时能够再次加载进行使用。与memcached同样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操做写入追加的记录文件,而且在此基础上实现了master-slave(主从)同步。vim
Redis支持数据库备份。缓存
Redis性能极高,读的速度是110000次/s,写的速度是8100次/s。安全
Redis丰富的数据类型(String、Lists、Hashes、Sets、Ordered Sets)。服务器
Redis的全部操做都是原子性的,要么成功执行、要么彻底失败不执行,多个操做支持事务,即MULTI和EXEC指令包起来。并发
Redis有丰富的特性,支持publish/subscribe(发布/订阅者模式),通知,key过时等特性。socket
相同点:都是NoSQl数据库,数据存到内存,读取速度快 好处以下: 1.减小数据库压力,提高访问速度 2.在数据挂掉的状况下,仍能保证业务正常运行一段时间,提高安全性 不一样点: (1)类型 memcached:类型单一,只能存字符串"key为字符串"="value也为字符串" redis:支持五大类型:string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)、hash(哈希类型) (2)持久化 memcached:断电数据丢失 redis:支持持久化,单独开一个进程完成持久化,要保持性能就须要关闭持久化,不少公司并不使用持久化功能
String字符串:能够包含任何数据,包括图片以及序列化对象,一个键最大能存储512MB。
List列表:简单的字符串列表,按照插入顺序排序,能够从两段进行添加,相似于双向链表,列表还能够进行阻塞。
Hash散列表:一个String类型的key和value的映射表,hash特别适合存储对象,类比python字典。
Set集合:字符串类型的无序且不重复集合。集合是经过哈希表实现,因此添加、删除、查找的时间复杂度都是O(1)。
Zset有序集合:zset和set同样,不一样的是每一个元素会关联一个double类型的分数,redis正是经过对分数的排序对集合进行有序存储。
(1)Redis安装
$ wget http://download.redis.io/releases/redis-5.0.2.tar.gz $ tar xzf redis-5.0.2.tar.gz $ cd redis-5.0.2 $ make # 编译redis程序
(2)Redis启动
通常启动reids-server都须要结合配置文件来启动。这样在配置文件中的配置就会生效在启动的redis服务中。
$ pwd /Users/hqs/redis-5.0.2 $ src/redis-server redis.conf # 启动redis服务 # 启动新终端,使用内置的客户端与redis进行交互 $ pwd /Users/hqs/redis-5.0.2 $ src/redis-cli 127.0.0.1:6379> set name 'bobo' OK 127.0.0.1:6379> get name "bobo"
能够经过redis-cli进入交互模式,使用config命令查看或设置配置项。也能够进入配置文件用vim编辑器进行修改。
# 获取全部配置项 reids 127.0.0.1:6379> config get * # 获取单个配置项 redis 127.0.0.1:6379> config get loglevel # 编辑配置 redis 127.0.0.1:6379> config set loglevel "notice"
首先须要下载安装redis模块:pip3 install redis
Redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令。
Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
Redis链接实例是线程安全的,能够直接将redis链接实例设置为一个全局变量,直接使用。
若是须要另外一个Redis实例(or Redis数据库)时,就须要从新建立redis链接实例来获取一个新的链接。
链接redis,加上decode_response=True,写入的键值对中的value为str类型,不加这个参数写入的则为字节类型。
class Redis(object): def __init__(self, host='localhost', port=6379, db=0, password=None, socket_timeout=None, socket_connect_timeout=None, socket_keepalive=None, socket_keepalive_options=None, connection_pool=None, unix_socket_path=None, encoding='utf-8', encoding_errors='strict', charset=None, errors=None, decode_responses=False, retry_on_timeout=False, ssl=False, ssl_keyfile=None, ssl_certfile=None, ssl_cert_reqs='required', ssl_ca_certs=None, max_connections=None, single_connection_client=False, health_check_interval=0):
默认host是'localhost',默认端口是6379。db以数字呈现,默认值是0,配置了16个db,能够经过配置db来切换到对应的数据库,至关于对内存中的大redis进行分块。
password是数据库密码,socket_timeout是超时时间,socket_connect_timeout是链接超时数。
connection_pool是链接池,max_connection是最大链接数。
decode_responses很重要,默认值是False,若改成True,则从redis取出的值都是字符串。
import redis """ conn = redis.Redis(host='127.0.0.1', port=6379) # 设置值 conn.set("n1", "v1") conn.hset("n2", "k2", "v2") ret1 = conn.get('n1') ret2 = conn.hget('n2', 'k2') print(ret1, ret2) # 输出:b'v1' b'v2' """ conn = redis.Redis(host='127.0.0.1', port=6379, decode_responses=True) # 设置值 conn.set("n1", "v1") conn.hset("n2", "k2", "v2") ret1 = conn.get('n1') ret2 = conn.hget('n2', 'k2') print(ret1, ret2) # 输出:v1 v2
Redis set命令用于在redis中设置值,不存在则建立,存在则修改。
Redis hset命令用于在哈希表中字段赋值。不存在则建立新的哈希表,已存在于哈希表中旧值被覆盖。
Redis get 命令用于获取指定 key 的值。返回key的值。若是 key 不存在,返回 nil 。若是key 储存的值不是字符串类型,返回一个错误。
Redis hget 命令用于返回哈希表中指定字段的值。返回给定字段的值。若是给定字段或key不存在,返回nil。
Redis Hmset 命令用于同时将多个 field-value (字段-值)对设置到哈希表中。此命令会覆盖哈希表中已存在的字段。若是哈希表不存在,会建立一个空哈希表,并执行 HMSET 操做。
import redis conn = redis.Redis(host='127.0.0.1', port=6379, decode_responses=True) conn.hmset("n3", {"k3": "v3", "k4": "v4"}) # 单条单条取 ret3 = conn.hget("n3", "k3") ret4 = conn.hget("n3", "k4") print(ret3, ret4) # v3 v4 # 全取 ret5 = conn.hgetall("n3") print(ret5) # {'k3': 'v3', 'k4': 'v4'}
redis-py使用connection pool来管理对一个redis server的全部链接,避免每次创建、释放链接的开销。
默认,每一个Redis实例都会维护一个本身的链接池。能够直接创建一个链接池,而后做为参数Redis,这样就能够实现多个Redis实例共享一个链接池
import redis pool = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True, max_connections=10) # 最大链接数 conn = redis.Redis(connection_pool=pool) ret = conn.get("n1") print(ret) # 输出:v1
若是想要并发操做,就须要写成单列,以模块导入就是一个单例,把他作成单例,写在一个文件里面,import它就是一个单例。
Redis提供了发布订阅功能,能够用于消息的传输,Redis的发布订阅机制包括三个部分:发布者、订阅者和Channel。
发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。
Redis的这种发布订阅机制与基于主题的发布订阅相似,Channel至关于主题。
redis采用publish命令发送消息,其返回值是接收到该消息的订阅者的数量。
import redis # 建立链接 conn = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True) # 建立发布者 conn.publish('hqs', 'Hello world!!')
redis采用subscribe命令订阅某频道,返回值包含客户端订阅的频道、目前已订阅的频道数量、接收到的消息(subscribe表示已经成功订阅某频道)。
import redis # 建立链接 conn = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True) # 第一步:生成一个订阅者对象 pubsub = conn.pubsub() # 第二步:订阅一个消息(实质就是监听这个键) pubsub.subscribe('hqs') # 第三步:死循环一直等待监听结果 while True: print("working~~~~") msg = pubsub.parse_response() print(msg)
先执行生成三个订阅者:
再用发布者发布消息,订阅者输出以下: