redis入门指南
第一章 简介
字典形式存储,数据结构无法嵌套。更贴近程序。
数据存在内存中,需要持久化,异步写入硬盘。常作为缓存、队列。
所有操作都是原子的。
可以设置key的生存时间、最大内存、阻塞式读取、发布/订阅模式
多数据库
select命令更换数据库,数字编码,无法命名。默认链接0号。
不支持访问密码,全访问/不访问
数据库之间不完全隔离,更像是命名空间。最好放相关的数据,如生产/测试
不同应用应该用不同的redis实例来存储。
存储结构
不同数据结构,有不同命令前缀,不能混着用
换言之不同前缀的set,也就声明了不同数据结构
字符串string
散列hash - H
列表list - L
集合set - S
有序集合zset - Z
key命名
对象类型:对象ID:对象属性
,多个单词用.
分隔
keys * 遍历存的所有的key
第二章 数据类型
字符串
最多512m
set key value
get key
incr key 递增
exists key
del key [key...]
hash
key是字典名,里面有字段field和字段值value
字段值只能是字符串。
hset key field value 插入/更新
hget key field
hmset key field value [key value…] 多存多取
hmget ...
hgetall key
hexists key field
hsetnx key field value 不存在则赋值
hincrby key field increment 增加数字
hdel key field [field ...]
hlen key 数量
列表
可以向列表两端添加元素,或获取某个片段。
内部用双向链表,所以越接近两端,访问速度越快,中间或索引访问很慢。
更适合新鲜事、排名、记录日志。
lpush key value [value...] rpush key value [value...]
lpop key
rpop key
llen key
lrange key start stop 支持负索引,最右是-1,lrange key 0 -1就是获取全部
lrem key count value 删除前count个值为value的元素,返回实际删除个数
count>0,从左;<0从右,=0,删除所有
lindex key index 获取索引值
ltrim key start end 只保留选中片段
linsert key before/after pivot value 从左往右在第一个pivot前/后插入value
rpoplpush source destination source列表右边弹出,destination左边插入 可以做一个执行堆栈
集合
每个元素不同,且没有顺序。可以并、交、差。
底层用key为空的hash。
适合文章标签之类的
sadd key member [member…] 已存在会忽略,返回增加了多少元素
srem key member [member...]
smembers key 获取所有元素
scard key 元素个数
sismember key member 判断是否在集合中
spop key 随机弹出一个元素
运算
sdiff key [key...]
差,A-B
sinter key [key...]
交,A∩B
sunion key [key...]
并,A∪B
有序集合
集合每个元素都关联一个分数,不同元素可以分数相同。
底层是hash表+跳跃表,读取中间位置也很快
跳跃表:每个节点随机有多少个节点,来链接后面
可以方便的调整某个元素位置,但比列表更占内存。
zadd key score member [score member ...]
zscore key member 获得元素分数
zrange key start stop [withscores] 获得排名在某范围为元素,含两端
有withscores会带上分数
zincrby key increment member 增加某个元素分数
zcard key 获得集合元素数量
zcount key min max 指定分数范围内元素个数
第四章 进阶
4.1 事务multi/exec
一组命令的集合,要么都执行,要么不执行。
而且保证执行过程中,无法被其他命令插入
但执行失败了无法回滚,得手动收拾烂摊子。
如果中间命令加入成功,会返回queued
错误
语法错误
返回错误,然后后面命令就不执行了
运行错误
其他命令照样执行(前后)
锁:watch
就是监听一个值,如果被修改了,之后的事物就不会再进行了。
然后要手动回滚+重新运行函数
可以在事务一半手动unwatch放开
4.2 过期时间expire
expire key seconds
精确到秒
pexpire key ms,精确到毫秒
ttl key
查询还有多久会被删除 被删了之后返回-2,如果没有设置过期时间,返回-1
persist key 取消过期时间
最大可用内存
maxmemory
超过了会lru,最近最少使用,来删掉不用的
访问频率限制
列表,记录用户最近10次访问时间。如果最早的访问在1分钟内,就报错。
4.3 排序sort
有序集合适合场景,是大数据排序。
sort key
集合、列表、有序集合
sort key alpha,根据字母排序
没有的话就转成双精度浮点数来排序
sort key desc 降序
sort key by field->value
field里面必须有*
,会根据*
的值来排序。
sort tag by post:*->time
在其他地方,或者没有*
,都不能排序
… get field->value
排序后返回field里面的*,对应的内容
sort tag by post:*->time get post:*->title
id是#
… store ${value} 来把结果存到某个变量里
性能优化
复杂度是O(n+mlog(m))
,m是要返回元素个数,n是要排序的元素个数
待排序要少
取出来的要少
数据量大,用store缓存结果
4.4 消息通知
任务队列
用独立线程来放队列,队列两边是生产者和消费者
生产者producer,给任务的人。把任务放进任务队列
消费者consumer,做任务的人。从队列读任务并执行
可以有多个消费者
brpop queue 0,没有元素就会一直阻塞,就不用空数组还拼命读了
0是超时时间,没新的元素,就会永远堵塞
优先级队列
blpop key [key…] timeout
同时检测多个键,所有键都没有元素就堵塞。
不然从左到右读取。因此优先的队列可以放在左边
发布/订阅
发布:publish channel message
订阅:subscribe channel [channel...]
订阅者无法获得订阅之前的消息
4.5 管道pipelining
为了减少网络传输,最好一口气发多条命令,然后一次性把结果返回
4.6 空间优化
数量少的时候,用效率更低,但占用空间更少的数据结构。到了一定数量再换回原本数据结构。
转换过程不可逆,数量减少了依然保持原本的数据结构。
字符串
小于64位有符号整数,用long类型。
能节约一半空间
sdshdr类型,包括了字符串长度、buf剩余空间、内容
redisObject
启动时会预先建立10000个数字,作为共享对象。就10000内只用存指针
即存小数字不用额外内存。
键值内容不超过39字节,用redis_encoding-embstr编码
超过了用redis_encoding_raw编码
散列类型
key/value/总数,少于hash-max-ziplist-entires
用redis_encoding_ziplist存
有一个超过了,就用redis_encoding_ht
redis_encoding_ziplist
存前一个元素大小,方便倒序找
编码类型、元素大小、是否数字类型(更加省空间)
实际内容
实际存,就是一个列表,field、value并列。要找的话从头一个个找
列表类型
redis_encoding_linkedlist,双向链表
redis_encoding_ziplist
redis_encoding_quicklist
将长列表变成若干链表组织的ziplist
集合类型
小于set-max-intset-entires用redis_encoding_intset,多了用redis_encoding_ht
redis_encoding_intset
有序存储,二分查找。
有序集合
小了用ziplist,不然是skiplist
redis_encoding_skiplist
用hash和跳表来存储。
hash表,存元素值和元素分数
跳表,存分数到元素值的映射
第六章 脚本
可以用Lua语言,写脚本,然后传到redis中执行
把逻辑用脚本实现,程序就更容易升级和扩展
第七章 持久化
缓存穿透:查一个数据库里面不存在的东西,找不到,于是就不断请求redis,再不断请求数据库,导致数据库宕机
可以返回一个空,就每次查询,redis直接返回查不到
缓存雪崩:很多缓存同一时间失效,然后redis同时请求数据库一堆内容,导致数据库宕机
每个缓存失效时间要设置的不同,不能同时失效
redis支持两种持久化:
RDB:根据规则,定时把内存数据存在硬盘上
AOF:记录执行了哪些命令
一般两者一起用
RDB
根据规则生成快照(snapshotting),记录修改了哪些地方
异常退出,就只会丢失最后一次快照后更改的内容。
规则
直接执行save,同步存
bgsave,异步存
配置文件中规定更新时间
save 900 1,900s内有一次以上改动,就更新。
多条规则是或
关系
flushall,刷新。清除数据库所有数据,执行快照
主从模式,复制时快照
快照原理
fork()复制当前进程副本
子进程开始把内存中的数据写入硬盘中的临时文件
这是经过压缩的数据,占用空间会小于内存大小
写完所有数据,才把临时文件替换旧dump.rdb文件。
换言之,任何时刻rdb文件都是完整的
写时复制:父子进程共享同一片内存,父进程要修改某一部分,操作系统就复制这部分数据给他用。
因此fork时内存不会变大一倍,因此可以申请超过可用内存的空间。
如果拍快照的时候疯狂写入,那么就会导致内存占用明显变大,导致内存溢出。
换言之快照存的是,fork的那一刻的数据
AOF
把每一条redis命令记录进appendonly.aof文件。需要手动开启。
aof纯文本,记录客户端发送的原始通信协议内容。
但是会有冗余命令,因此每当达到一定条件,自动重写aof文件
重写过程只和内存中数据有关,和之前aof文件无关。
redis启动时,会逐个执行aof文件命令,把硬盘数据加载到内存中。
同步硬盘
写入硬盘,是写入了硬盘的缓存,一般操作系统30s会同步一次进入硬盘。
也可以主动要求系统,把缓存内容同步到硬盘中。
一般使用默认值,每秒同步一次即可。
第八章 集群
避免单点故障
要扩容
8.1复制
主从结构。主master数据库,可以读写,主要是读;从slave数据库,只读。
主数据改动会同步给从。一主可有多从,一从只能有一主。主从关系可更改。
从也可以为主,下面跟从数据库。
适合读多写少的场景。
info replictaion来查看信息
同步
一开始的同步,是主数据库异步在后台保存快照,即RDB持久化。同时把接收到的命令缓存起来。
然后复制给从数据库,从数据库从快照和命令缓存恢复。
同步过程中,请求数据的命令都回复错误。即不让读数据。
此后主数据库,就同步修改命令,给从数据库
乐观复制
允许主从之间有数据不同步,但最终会同步。
复制数据是异步的,因此会有数据不一致的时间窗口。
无硬盘复制
不论有没有开rdb,快照都会拍。那么下次启动,主数据库就会以快照恢复数据。
如果没开rdb,就可能恢复了错误时间点的数据
每次和数据库同步,redis都会执行一次快照,导致性能降低
无硬盘复制,初始化时,不存硬盘,直接通过网络发送给从数据库,绕开硬盘性能瓶颈。
增量复制
从数据库断开连接,之后连接上主,如果再快照走一遍,就很浪费。
存主数据库的运行id,每个实例对应一个id,重启生成新的
主数据库记录每个命令,放在一个积压队列里面,记录偏移量(指针)
从数据库接收主数据库命令,也要记录命令的id(偏移量)
重连后
判断运行id是否和自己的一致,之前是不是和自己在同步的
命令偏移量比对一下,把增量命令发给从
如果不满足,就全部同步
挤压队列就是固定长度的循环队列。越长允许断线时间越长。
8.2哨兵
主挂了怎么办?哨兵自动化监控+故障恢复
如果主挂了,就选一个从当主,如果主再连上,就自动变成从。
一般一个节点一个哨兵盯着。哨兵环境尽可能模拟数据库环境。
定期info获取当前数据库的信息。
有新节点自动发现,也能获取从数据库列表,然后同样方式建立连接
定期和别的哨兵沟通,分享已有信息、主数据库的配置版本
有新哨兵就能这样发现。
ping其他哨兵和数据库,监控有没有停止服务。
故障处理
如果被ping的对方超时没有,就认为其 主观下线。
即从这个哨兵的视角看来它是下线了
然后就把消息同步给其他哨兵。当认为 主观下线的人超过一半,就认为 客观下线了
选举领头哨兵节点,进行故障恢复
选举方法
发现客观下线的节点,告诉每个哨兵,选自己当节点
如果哨兵还没选过人,就选他
如果投票结果没有超过半数的,每个人参选人随机等一段时间,让别人投自己
恢复方法
停止服务的主数据库,从数据库当中挑选一个来当新的主
人为设置优先级高的当选
命令偏移量大,即最接近主数据库数据的当选
都一样就看id小的当选
8.3 集群
每个数据库拥有全部数据,那么存储容量就会受制于内存最小的数据库。
水瓶扩容,就是客户端分片,整个数据分布在n个节点中。【有点像哈希表】
可以预分片,先规划好哪些存哪里。
Cluster
比客户端分片性能更优、更方便
只能用默认0号数据库
一个集群至少3个主数据库
每个节点都有自己的运行ID,是集群中的身份证。每个节点都完全独立。
初始化
redis-trib.rb,以客户端形式ping所有节点
向每个节点发送cluster meet命令,告诉其他节点的ip和port
分配主从节点,主从不在一个ip,主尽量不在一个ip,容灾能力。
主数据库分配插槽,哪些键归哪些节点负责
分配插槽
没规定的话,插槽连续。
设定键的时候,可以用{}
包裹标签,这样就会被分配到同一个插槽当中了。同一个节点,才能支持多健的批量操作。
节点增加
给新节点发送,集群中任意一个节点的ip和port。相当于找个人引荐
其他人都能顺着找到。
找不到就跳转
类似于路由,这里找不到就跳转,重新定向。比如在同步数据之类的时候。
不过这样就增加了请求次数,因此可以加个缓存。
故障恢复
定期抽取5节点,选择最久没ping的ping一下
一段时间内没回复,人为疑似下线(主观下线)
如果整个集群一半都认为下线,就标记为下线,启动故障恢复。
下线的从数据库里面,找一个从,变成主。也是用哨兵的那个算法
第九章 管理
9.1 安全
没有多少安全工作。需要运行在“可信环境”中。redis默认接受任何地址发来的请求。
生产环境中也不能外界直接连接到redis服务器,需要应用程序进行中转。
密码
配置密码,每次链接都要发送密码。
但redis性能高且密码错误后不会主动延迟。所以可以穷举密码,一秒尝试十几万个。
主数据库设置了密码,从数据库要配置相应密码,就能自动认证。
通信协议
简单协议,就是用空格断句,平常命令行敲的。
统一请求回复,AOF和主从复制的统一请求协议
返回值是一样的
9.3第三方管理工具
耗时命令日志slow log
monitor,调试和纠错,监控所有命令
rdbtools,快照文件分析,到处json数据、占用内存情况等。
Last updated
Was this helpful?