我的个人主页:蚂蚁的宝藏
传统数据库遵循ACID原则,而NOSQL遵循CAP原则。
Consistency(一致性): 所有节点在同一时间具有相同的数据
Availability(可用性):集群中一部分节点失效后,集群整体保证响应客服端的读写请求
Partition tolerance(分区容灾性):系统中任意信息的丢失或失败不会影响系统继续运行。
任何时候,最多满足以上两点,在分布式存储中,分区容灾性是必须的,所以在一致性和可用性上要做出权衡。redis在一致性上做出了妥协,采用结果最终一致性的弱化处理数据异步复制。
redis演变
复制
redis提供复制功能,用户可以通过复制master来创建多个slave。只要主从服务器之间通信正常,会保持相同的数据,master会一直将自身的数据更新至slave。解决了master的读压力。
哨兵
redis sentinel 在分布式系统中,监控主从服务器,在master下线,会自动进行故障转移,保证了系统的高可用。
集群(proxy)
通过增加proxy层来进行数据分片,减轻redis的写压力。但是proxy层无法保证高可用,维护成本增加。
集群(直连型)
去除proxy层,无中心架构;通过选举制实现故障转移,完成slave到master的角色转换;节点可动态扩张;通过增加slave节点实现高可用;数据按照slot存储,节点数据可共享。
redis数据结构
redis以 key-value 键值对 作为存储方式。支持多种数据结构。
String
string是redis使用最多的数据结构之一,value大小不能超过512M,set的时候,可以不用引号。
值可以是字符串,整数,浮点数。
若值为数字,做运算时,redis会自动进行转换。
命令 | 说明 |
---|---|
SET key value | 定义key并赋值 |
GET key | 获取key的值 |
DEL key | 删除key |
APPEND key value | 末尾追加,字符串拼接 |
STRLEN key | 获取字符串长度 |
INCR key | 自增 |
DECR key | 自减 |
INCRBY key increment | 按指定步长增长 |
DECRBY key increment | 按指定步长减少 |
SETEX key seconds value | 同时设置过期时间,同EXPIRE,可使用TTL查看剩余时间 |
List
链表上的每个节点包含一个字符串。链表的两端都可以进行读写。
命令 | 说明 |
---|---|
LPUSH key value | 向链表左端添加元素value |
RPUSH key value | 向链表右端添加元素value |
LPOP key | 从链表左侧读取并移除元素 |
RPOP key | 从链表右侧读取并移除元素 |
LINDEX key index | 按index读取vaule |
LRANGE key start stop | 读取指定范围的元素 |
BRPOP key[key ...] timeout | 阻塞的方式从链表右侧弹出元素,如果元素为空,阻塞等待,直到超时或者有值返回 |
BLPOP key[key ...] timeout | 阻塞的方式从链表右侧弹出元素,如果元素为空,阻塞等待,直到超时或者有值返回 |
Set
无序且无重复的字符串集合
常用命令:
命令 | 说明 |
---|---|
SADD key value | 向key中添加元素value,成功返回1,失败返回0 |
SREM key value | 从key中移除元素value,成功1,失败0 |
SMEMBERS key | 列出key中所有元素 |
SISMEMBER key value | 判断key中是否存在元素value,没找到0 |
zset
有序的set集合,通过浮点数score来实现。
元素a,b,若a.score>b.score,则a>b;若a.score=b.score,a>b,则a>b。
命令 | 说明 |
---|---|
ZADD key score member | 向key集合中插入memeber,设置score |
ZRANGE key start stop | 读取指定范围类元素 |
ZRANGEBYSCORE key min man | 按照score的范围读取元素 |
ZREM key member | 移除元素 |
hash
包含key,value的散列表。
命令 | 说明 |
---|---|
HMSET key field value [field value ...] | 添加值 |
HGET key field | 取值 |
HMGET key field [field ...] | 取值 |
HGETALL key | 获取所有元素 |
HDEL key field [field ...] | 删除指定字段 |
事务
因为redis是单线程来处理所有client的请求,所以redis对事务的处理比较简单,通过一个类似阻塞队列的东西保证一个client发起的事务中的命令可以顺序执行,中间不会插入其他client的命令。
通过 EXEC 命令来开启一个事务,DISCARD取消事务,EXEC结束事务
发布订阅
发布订阅(pub/sub)是类似观察者模式的一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接收消息。
ps.网上找的图
SUBSCRIBE 订阅主题,开启通道,获取消息
PUBLISH 推送消息
UNSUBSCRIBE 取消主题
持久化
为了防止服务宕机内存数据丢失,redis提供了三种持久化方式:RDB(deafult),AOF,RDB和AOF同时使用。
RDB:
定时调用 rdbSave 函数,将内存数据写入一个dump.rdb,如果文件存在,替换。
操作 rdbSave 函数有两种命令,SAVE和BGSAVE
SAVE命令会直接调用rdbSave函数,在RDB文件保存期间,主进程会被阻塞,服务端无法处理客户端请求,保存完成,唤醒主线程。
BGSAVE命令会先fork一个子进程,由子进程调用 rdbSave 函数,不会阻塞主进程,服务端仍可服务客户端,保存完成,子进程会向主进程发送通知。
在redis服务启动或重启时,会调用 rdbLoad 函数,加载磁盘中的RDB文件到内存中。
+-------+-------------+-----------+-----------------+-----+-----------+
| REDIS | RDB-VERSION | SELECT-DB | KEY-VALUE-PAIRS | EOF | CHECK-SUM |
+-------+-------------+-----------+-----------------+-----+-----------+
|<-------- DB-DATA ---------->|
保存策略:
save 900 10 #900s内超过10个key被修改,发起快照保存。
AOF:
append-only-file,以协议(RESP)文本的方式,把数据库的命令操作参数追加到aof文件中。
这个过程分为三步:
1.命令传播:Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。
2.缓存追加:AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。
3.文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话, fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。
AOF支持三种保存模式:
1.AOF_FSYNC_NO :不保存。
2.AOF_FSYNC_EVERYSEC :每一秒钟保存一次。(不阻塞主进程)
3.AOF_FSYNC_ALWAYS :每执行一个命令保存一次。(阻塞主进程)
参考文献 -- 《Redis设计与实现》
可以看到 rdb文件中存储的数据,aof文件中存储的是命令+数据,而且aof的文件可读性更高。
除此之外,AOF的更新频率高于RDB,优先加载aof。
复制
redis的复制方式有两种,一种是主(master)-从(slave),一种是从(slave)-从(slave)。
配置方式:
# 复制一份配置文件 cp redis.conf slave.conf
# 修改slave的配置 slaveof ip port
# 修改master的配置 bind 0.0.0.0
# 启动slave ./redis-server ../slave.conf &
集群
在redis集群中,引入了hash槽-slot的概念。
集群中的节点node,共同分配16384个slot,所以集群中节点最多只能有16384个,所有的key都对映射到对应的slot中。
redisCluster通过CRC16(key)/16384 来计算key属于哪个槽。
通过为每个node分片不同数量的slot,按照槽来分片,可以控制不同节点的数据量和请求数。
redisCluster的特点:
1.节点自动发现
2.slave->master 选举,集群容错
3.支持rehsard在线分片
4.节点直连型,不需要proxy层
5.所有节点彼此互连(ping-pong)
数据迁移
当我们需要新增节点时,只需要从以往节点中分配部分slot到新节点;需要删除节点时,先把该节点的slot转移到其他节点,然后删除即可。这个功能极大方便了集群的线性扩展或缩容,并不会造成集群不可用的状态。
在slot迁移过程中,masterA状态为MIGRATING,masterB状态为IMPORTING。
真正改变node映射的是键空间迁移。
src目录下的集群管理命令redis-trib.rb支持reshard的手动在线迁移方式。
命令 | 说明 |
---|---|
call | 在集群全部节点上执行命令 |
set-timeout | 设置集群节点间心跳连接的超时时间 |
del-node | 从集群中删除节点 |
reshard | 在线迁移slot |
check | 检查集群 |
import | 将外部redis数据导入集群 |
add-node | 将新节点加入集群 |
create | 创建集群 |
info | 查看集群信息 |
fix | 修复集群 |
rebalance | 自动平分集群节点slot数量 |