Redis数据库
1.完全基于内存读写的非关系型数据库(支持持久化存储)
【1】key:value键值对方式组织数据,所有的键值对都有设置过期的功能<弱事务型的数据库>;
【2】核心操作都采用单进程单线程的数据库;
【3】应用:
1.缓存;
2.并发计数;
3.排行榜;
4.生产者消费者模型
5.增量式爬虫
......
【4】主从复制,哨兵模式!
<永远记住Redis是单进程单线程的!>
【5】Redis对于过期的key淘汰策略:
(1)Redis主动删除:
将带过期时间的key存在一个独立的hash中,默认每100毫秒进行过期扫描:
1.每次随机选20个key进行判断
2.检查过期的时间,删除已过期的key
3.如果删除的比例超过1/4则重复1-3的操作;<默认每次循环的主动删除用时小于25ms>
---------------------------------------------------------------------------------
Q:【场景】当大量的key同时过期<过期时间太集中>,Redis会有卡顿问题;
A:【方案】set key value ex time + 时间偏移量
---------------------------------------------------------------------------------
(2)Redis惰性删除:
1.当get key时,如果key过期了,则直接删除;
# Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据?
2.Redis配置maxmemory检查,当Redis的使用内存量大于maxmemory时,再次主动进行对过期key进行淘汰;
1)noeviction: 拒绝写服务<默认配置>;
2)volatile-lru:淘汰过期及较少使用的key;
1.1Python实现 LRU Cache
【1】LRU: 最近最少使用算法;
【2】算法:
class Lru:
def __init__(self, capacity):
self.cache = {}
self.cache_list = []
self.capacity = capacity
def get_cache(self, key):
if key in self.cache_list:
if key == self.cache_list[-1]:
return self.cache[key]
else:
self.cache_list.remove(key)
self.cache_list.append(key)
else:
return 'this key is no cache'
def set_cache(self, key, value, expire=60):
if len(self.cache) == self.capacity:
for i in range(len(self.capacity // 2)):
self.cache.pop(self.cache_list.pop(0))
else:
self.cache[key] = value
self.cache_list.append(key)
return value
2.基础
【1】Redis默认0-15库;非关系型数据库的数据查找一定是根据具体的key值精确查找;
【2】字符串类型:
set key value [ex time] #为一个键值对添加过期时间
get key
重点:字符串类型数字操作:
incrby key number #加法
decrby key number #减法
incr/decr key #自增/自减1
key的一般命名规范如:name:email
【3】列表数据类型:
列表中的元素必须是字符串;支持两头操作,尽量避免在列表中间操作数据;
lpush/rpush key value1 value2 value3.... #插入数据
lrange key start stop #查看数据
-------------------------------------------------------------------------------------
【应用场景】
1.生产者消费者模型<中间层:broker--用Redis的list类型的blpop/brpop模拟中间层的消息队列>:
blpop/brpop key timeout
2.利用列表可以遍历数据
-------------------------------------------------------------------------------------
【4】hash散列类型<有压缩的特点>
key {field1:value1,field2:value2... ...}
在特定条件下<字段 个数小于512个,value不能超过64bytes>节约内存空间!
hset key field1 value1 field2 value2.....
hget key field
-------------------------------------------------------------------------------------
【应用场景】
1.用作缓存;
2.字典为什么是无序的,因为要进行rehash;
【6】通过Redis的位图操作,进行数据统计
setbit key value
【7】 集合操作:
SADD key value1 value2 ... ...
-------------------------------------------------------------------------------------
【应用场景】
1.因为集合有自动去重的功能,可以实现增量式爬虫;
3.Python交互Redis
import redis #导入redis模块
r = redis.Redis(host='127.0.0.1',port=6379,db=0,[password='xxx']) #创建连接对象
r.方法名() #调用方法进行操作
r.close() #关闭Redis的连接对象
3.1Python交互Redis
import pymsql #导入pymysql模块
db = pymsql.connect(host='',post='',user='',password='',database='',charset='') #创建连接
cur = db.curcors() #创建游标
cur.execute('sql') #使用游标操作sql语句
db.commit() #如果是写操作需要commit
cur.close() #关闭游标对象
db.close() #关闭连接对象
4.Redis事务
【1】Redis的事务单独隔离操作,事务中的所有命令会被序列化、按顺序执行<按照客户端隔离> ;
MULTI #开启事务
命令1
......
EXEC #提交到数据库执行
DISCARD #取消事务
【2】事务的重点:
事务的开启后,Redis-server会开启对应的命令队列<按照客户端去隔离命令队列>,EXEC后Redis-server开始执行队列中的命令;
(1)流水线<编程语言客户端中才支持pipeline功能>:
客户端技术,将事务的命令存储在客户端,当EXEC时再将客户端的事务序列发送至Redis-server执行,从而减少通信,提升效率;
python操作Redis事务<流水线操作事务>:
with r.pipeline(transaction=True) as pipe:
pipe.multi()
pipe.incr('key')
pipe.incr('key')
values=pipe.execute()
(2)【重点】Redis的乐观锁<WATCH>: 在创建redis事务时,可对指定的key进行监听,命令提交时,如果被监听的key没有被修改时,才能提交成功;
如果在本次事务在未EXEC之前,被监听的KEY已经被修改,则本次事务的所有Redis操作全部失败;
-------------------------------------------------------------------------------------
<防止资源争夺问题>
WATCH key
multi
incr key
EXEC
【悲观锁】:比如MySQL的行级锁或者表级锁;
5.Redis的数据持久化
【1】内存的数据备份到磁盘;
【2】方法一:RDB模式(默认开启)
创建RDB文件方式:
(1)Redis用户主动备份:SAVE 或者 BGSAVE;
(2)设置配置文件条件满足时自动保存(使用最多);
RDB的缺点:自动创建RDB文件比较频繁,否则会严重影响服务器的性能,可能会丢失数据;
【3】方法二:AOF
AOF存储的是Redis命令,不是真实的数据<需要手动开启配置进行存储>;
AOF持久化的原理:每次修改数据库的命令被执行时,将命令写到默认配置的AOF文件;
6.Redis的主从复制
【1】'从'只能接受'读'请求;
'主'可以进行'读写'请求;
【2】作用:分担了读的压力(高并发);
避免单点问题【如果系统中'主Redis'挂了,'从Redis'能够接替成为'主Redis'】
【3】如果master挂了怎么办?
sentinel哨兵:自动化的维护当master挂了之后,维护slave作为'主Redis';