redis简介
redis单纯程模型,支持主从模式,提高可用性,是一个开源项目,经常用来当一个数据结构服务器。其是内存级别的缓存服务器并可实现持久化功能. 据称一百万的变量存储(字串)占用100M内存空间,单台redis服务器可达到5万并发的能力。
redis与memcache的对比
redis的优势
- 支持丰富的操作
- 主从复制和集群
- 就地更新操作
- 支持持久化(磁盘),避免雪崩效应
memcache优势
- 多线程,善用多核CPU,更少的阻塞操作
- 更少的内存开销
- 更少的内存分配压力
- 可能有更少的内存碎片
redis的组件
redis-server
redis-cli
redis-benchmark
redis-check-dump & redis-check-aof
redis的工作端口
6379/TCP
redis-cli命令的参数
-
-h HOST
: 连接的主机地址或主机名 -
-p PORT
:连接的端口 -
-s socket
: 指定套接字 -
-a password
: 指定连接密码 -
-r <repeat>
: 指定命令运行多次
redis-cli中相关的命令
connection相关的命令
-
auth PASS
: 认证 -
ping
: 测试服务器是否在线 -
echo "string"
: 显示string -
quit
: 退出 -
select #
: 挑选指定的名称空间(即数据库) -
help @connection
: 获取与连接相关的命令帮助
-
与服务器端支持的命令
help @server
: 获取与服务器端相关的命令帮助bgsave
: 实现异步将数据集同步到磁盘上client getname
: 获取当前客户端的连接名client kill IP:PORT
: 指定IP:PORT可关闭相关的连接信息client list
: 查看客户端的连接信息
172.16.36.70:6379> client list id=5 addr=172.16.36.70:57606 fd=8 name= age=904 idle=879 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
“`-
client setname CONNECTION-NAME
: 设定当前连接的名称 -
info
: 查看当前服务器的状态信息 -
info memory
: 只显示memory段的相关信息 -
config resetstart
: 重置info中所统计的数据 -
config set PARAMETER value
: 运行时修改设定指定参数的值,只保存在内存中 -
config rewrite
: 将修改在内存中的参数值同步到配置文件中 -
config get dir
: 查看redis的文件保存目录 -
dbsize
: 显示数据库中所有键的数量 -
lastsave
: 用来获取最新一次save执行的时间戳 -
save
: 保存数据到磁盘 -
monitor
: 实时监控所接收到的请求 -
shutdown
: 将所有数据从内存同步到磁盘,并安全关闭 -
shutdown [nosave][save]
: 关闭程序并选择是否将数据同步到磁盘上 -
salveof HOST PORT
:配置主从,当前节点将变成从节点 -
slowlog
: 查看慢查询日志,需要开启慢查询日志功能 -
sync
: 复制功能的内建命令
与订阅相关的命令
-
help @pubsub
: 获取与订阅相关的命令 -
psubscribe
: 基于模式进行订阅 -
publish
: 向频道发送消息 -
subscribe CHANNEL
: 订阅一个频道
-
redis的认证功能
vim /etc/redis.conf
requirepass zhenping.com
重启redis服务
systemctl restart redis
连接redis并认证的方法
redis-cli -h 172.16.36.70
172.16.36.70:6379> select 0
(error) NOAUTH Authentication required.
172.16.36.70:6379> auth zhenping
OK
redis清空数据库
flushdb
: 清空当前库flushall
: 清空所有库[root@Centos7 ~]# redis-cli -h 172.16.36.70 172.16.36.70:6379> flushall OK 172.16.36.70:6379> flushdb OK
redis的事务功能
通过multi
,exec
,watch
等命令来实现事务功能,将多个命令打包,多个命令按顺序执行,并一次执行完成,并将执行结果一次性全部返回给客户端。redis事务不支持回滚操作,在事务中应避免发生错误(如命令写错等),事务了也将会执行失败。
-
multi
: 启动一个事务 -
exec
: 执行事务,一次性将事务中的所有操作执行完成后,返回给客户端 -
watch
: 乐观锁机制,在EXEC命令执行之前 ,用于监视指定数据键,如果监视的某任意键数据被修改,服务器拒绝执行事务
####建立一个事务
[root@Centos7 ~]# redis-cli -h 172.16.36.70
172.16.36.70:6379> multi
OK
172.16.36.70:6379> set ip 172.16.36.70
QUEUED
172.16.36.70:6379> get ip
QUEUED
172.16.36.70:6379> set prot 8080
QUEUED
172.16.36.70:6379> exec
1) OK
2) "172.16.36.70"
3) OK
####使用watch机制监控键
[root@Centos7 ~]# redis-cli -h 172.16.36.70
172.16.36.70:6379> watch ip
OK
172.16.36.70:6379> multi
OK
172.16.36.70:6379> set ip 172.16.36.71
QUEUED
172.16.36.70:6379> get ip
QUEUED
172.16.36.70:6379> exec
(nil)
说明: 当watch ip指令发出后,其它的请求操作改变了IP键的值,此时新发起的事务中,如果也要改变其值, 此事务申请将会失败
redis的发布和订阅功能(publish/subscribe)
发布和订阅功能被广泛用于构建即时通信应用,比如:网络聊天室和实时广播、实时提醒等。 订阅发布功能就能帮你很轻松地实现通知、监控程序
-
subsciribe CHANNEL_NAME
: 订阅一个频道 -
publish CHANNEL_NAME
: 向频道发送一个消息 -
unsubscribe CHANNEL_NAME
: 退订频道 -
psubscribe CHANNEL_NAME_PATTERN
: 基于正则表达式模式定义多个频道
1、订阅一个频道:
72.16.36.70:6379> subscribe news
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news"
3) (integer) 1
2、向频道发送消息
172.16.36.70:6379> publish news weizhenping
(integer) 1
3、频道会接收下来消息
[root@Centos7 ~]# redis-cli -h 172.16.36.70
172.16.36.70:6379> subscribe news
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news"
3) (integer) 1
1) "message"
2) "news"
3) "weizhenping" #此内容为频道发送过来的消息
基于模式的频道订阅示例
1、基于模式订阅频道
[root@Centos7 ~]# redis-cli -h 172.16.36.70
172.16.36.70:6379> PSUBSCRIBE news.i[to] #订阅了news.io,news,io两个频道
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "news.i[to]"
3) (integer) 1
2、向频道发送消息
172.16.36.70:6379> PUBLISH news.io hello
(integer) 1
3、频道会接收下来消息
[root@Centos7 ~]# redis-cli -h 172.16.36.70
172.16.36.70:6379> PSUBSCRIBE news.i[to]
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "news.i[to]"
3) (integer) 1
1) "pmessage"
2) "news.i[to]"
3) "news.io"
4) "hello"
redis的持久化功能
1、RDB(redisDB)
工作原理
RDB为snapshot(快照)存储机制,其也是redis默认的存储机制,按照事先定制的策略,周期性地将数据从内存中读取出来保存至磁盘,当到达
save
指令指定的时间,redis主进程将fork一个子进程,负责内存中的内容快照并保存到磁盘中。 Linux系统有写时复制机制,父进程与子进程会共享相同的物理页面,当父进程处理写请求时,操作系统为写的数据创建一个副本,因此子进程保存的数据一定是与时间点一致的数据。当子进程将快照写入临时文件后,会使用临时文件替换旧的文件,然后子进程完成退出 。保存的数据文件默认为dump.rdb
. 如果在SAVE周期之前停电了,会造成部分数据丢失。数据保存机制
-
save
: 在主线程中保存快照,保存时会阻塞所有客户端请求,每次将完整数据写至dump.rdb文件中,会带来大量的IO压力 -
bgsave
: 异步保存机制,在后端自动保存,其不会阻塞窝客户端请求
-
RDB相关的配置参数(/etc/redis/redis.conf)
-
stop-writes-on-bgsave-error yes
: 在基于快照备份时,一旦发生错误,是否停止写操作 -
rdbcompression yes
: rdb文件是否压缩来节约空间 -
rdbchecksum yes
: 是否对rdb的镜像文件做校验码检测,当redis启动时会根据事先保存好的校验码进行对比,保证数据的完整性 -
dbfilename dump.rdb
: 保存的文件名 -
dir /var/lib/redis/
: 文件保存目录 -
save ""
: 关闭rdb功能
-
2、AOF(append only file)
工作原理
redis以顺序IO的方式附加在文件的尾部,将每一次的写命令操作都通过write函数追加到文件后面,其是比RDB更好的持久化方案,但文件会变得越来越大。当redis重启时,可通过执行文件中的命令在内存中重建数据库
数据保存机制
-
bgrewriteaof
:AOF文件重写
,它不会读取正在使用的AOF文件,而是通过将内存中的数据以命令的方式保存至临时文件中,完成之后替换原来的AOF文件,这样可以减少AOF的大小
-
AOF重写过程
- 1、redis主进程通过fork机制创建子线程
- 2、子进程根据redis内存中现有的数据通过重建命令创建数据库于临时文件中
- 3、父进程继续接收客户请求,并会把这些请求中的写操作继续追加到原来的AOF文件中,额外地,也将新的写请求放置于一个缓冲队列中
- 4、子进程重写完成,会通知父进程,父进程把缓冲中的队列命令写到临时文件中
- 5、父进程用临时文件替换老的AOF文件
AOF相关的配置参数(/etc/redis/redis.conf)
-
appendonly no
: 是否启用AOF功能,yes表示启用 -
appendfilename "appendonly.aof"
: aof存储文件 -
appendfsync always
: 每次收到写命令,立即写入磁盘 -
appendfsync everysec
: 每秒钟写一次,推荐操作 -
appendfsync no
: append功能自己触发写操作,将所有操作都提交给OS,由操作系统决定什么时候写 -
no-appendfsync-no-rewrite no
: 在重写的过程中是否调用fsync -
auto-aof-rewrite-percentage 100
: 在aof文件已经是上次重写时的2倍大小,将自动启动重写操作 -
auto-aof-rewrite-min-size 64mb
: 当文件达到64MB才执行重写操作
RDB与AOF同时启用时: 1、bgsave和bgrewriteaof不会同时执行 2、在redis服务器启动用于恢复数据时,会优先使用AOF
-
redis的主从复制
1、redis的主从复制特点
- 一个master可以有多个slave
- 支持链式复制
- master以非阻塞方式同步数据至slave,意味着可同时与多个slave同步
2、复制的工作原理
- 1、主库会自己基于ping check机制来检查从库是否在线
- 2、如果从库在线就同步数据文件至从服务器端
- 3、从服务器也可以发送请求同步的请求,主库将启动一个线程,把内存中的数据同步给从库,从库将数据保存至文件中
- 4、从库再把文件装载到内存中,从而完成复制功能
3、主从相关配置(/etc/redis.conf)
-
slave-serve-stale-data yes
: 当主服务器连接不上了,从服务器是否可以使用过期数据响应 -
repl-diskless-sync no
: 是否基于diskless机制同步 -
slave-priority 100
: 指定从服务器优先级 -
min-slave-to-write 3
: 如果从节点小于三个,主服务器将拒绝写操作 -
min-slave-max-lag 10
: 从服务器不能晚于主服务器10秒钟,是否将停止复制
如果master使用了requirepass开启了认证功能,从服务器要使用masterauth <password>来连接,使用指定的密码进行认证
主从设置示例: 172.16.36.70 : 主redis服务 172.16.36.71 : 从redis服务 172.16.36.70配置 vim /etc/redis.conf bind 172.16.36.70 172.16.36.71配置: vim /etc/redis.conf bind 172.16.36.71 [root@Centos7 ~]# redis-cli -h 172.16.36.71 172.16.36.71:6379> SLAVEOF 172.16.36.70 6379 OK 172.16.36.71:6379> get ip #查看是否能获取到主库数据 "172.16.36.70" 172.16.36.71:6379> dbsize (integer) 3
-
redis高可用的实现
sentinel机制
工作原理
找一台专用的监控主机,即能提供监控又可以提供配置功能,如果发现master离线了,监控主机会从从节点选择新的主节点。为了不误判,setinel至少奇数个节点,同时监控。如果主节点不在线,多个setinel会协调一个新的主节点,以免发生误判,所有setinel每秒一次向所有服务器发送ping请求,判断节点是否在线。setinel是一个分布式系统,使用流言协议和投票协议来决定故障迁移。可以监控多组redis实例。
sentinel的功用
- 用于管理多个redis服务,实现HA
- 监控
- 通知
- 自动故障转移
工作过程
- 启用sentinel时, 首先服务器做自身初始化,运行redis-server中专用于sentinel功能中的代码
- 初始化sentinel状态,根据给定的配置文件,初始化监控的master服务列表(可以根据master的配置,获取从服务器节点)
- 创建连向Master的连接
sentinel下线机制
-
主观下线
: 一个sentinel实例判断出某节点下线 -
客观下线
: 多个sentinel节点协商后判断出某节点下线
-
setinel程序
redis-sentinel /path/to/sentinel.conf
redis-server /path/to/sentinel --sentinel
setinel的工作端口
26379/TCP
专用配置文件
/etc/redis-sentinel.conf
redis-sentinel.conf配置参数
prot 26379
dir /tmp
sentinel monitor mymaster 127.0.0.1 6379 2
mymaster: sentinel要监控的实例名称,此名称可以随意取 127.0.0.1 : 主节点的IP地址 6379 : 主节点的端口 2 : sentinel节点的票数,此值要大于sentinel节点数量的半数
-
sentinel down-after-milliseconds mymaster 30000
: 判断主节点不在线的默认超时时长,默认30秒 -
sentinel parallel-syncs mymaster 1
: 故障转移时最多能有多少个从服务器向主服务器发起同步请求 -
sentinel failover-timeout mymaster 180000
: 提升主节点的超时时长,表示提升新的主节点在3分钟内未完成,操作将失败
sentinel专用命令
-
sentinel masters
: 列出所有主服务器 -
sentinel slaves <master name>
: 获取所有当前redis实例中的从节点信息 -
sentinel get-master-addr-by name <master name>
:直接获取当前redis实例主节点的IP地址及端口
172.16.36.74:26379> sentinel get-master-addr-by-name mymaster 1) "172.16.36.72" 2) "6379"
-
sentinel reset
: 重置服务器所有状态 -
sentinel failover <master name>
: 手动实现故障转移
-
sentinel配置实例
实验环境说明:
172.16.36.70 : redis主节点
172.16.36.71 : redis从节点
172.16.36.72 : redis从节点
172.16.36.74 : sentinel节点1
172.16.36.75 : sentinel节点2
172.16.36.76 : sentinel节点3
####配置redis主节点
操作主机: 172.16.36.70
#vim /etc/redis.conf
bind 172.16.36.70
daemonize yes
启动服务
#redis-server /etc/redis.conf
[root@Centos7 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 172.16.36.70:6379 *:*
####配置redis从节点
操作主机: 172.16.36.71
#vim /etc/redis.conf
bind 172.16.36.71
daemonize yes
启动服务
#redis-server /etc/redis.conf
[root@Centos7 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 172.16.36.70:6379 *:*
配置主节点信息
[root@Centos7 ~]# redis-cli -h 172.16.36.71 -p 6379
172.16.36.71:6379> SLAVEOF 172.16.36.70 6379
OK
操作主机: 172.16.36.72
#vim /etc/redis.conf
bind 172.16.36.72
daemonize yes
启动服务
#redis-server /etc/redis.conf
[root@Centos7 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 172.16.36.70:6379 *:*
配置主节点信息
[root@Centos7 ~]# redis-cli -h 172.16.36.71 -p 6379
172.16.36.71:6379> SLAVEOF 172.16.36.70 6379
OK
####配置sentinel节点
操作主机: 172.16.36.74
# vim /etc/redis-sentinel.conf
port 26379
dir "/tmp"
daemonize yes
sentinel monitor mymaster 172.16.36.70 6379 2
sentinel parallel-syncs mymaster 3
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
启动服务
redis-sentinel /etc/redis-sentinel.conf
查看服务启动状态
users:(("master",2112,14))
[root@Centos7 ~]# ss -tln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:26379 *:*
操作主机: 172.16.36.75
# vim /etc/redis-sentinel.conf
port 26379
dir "/tmp"
daemonize yes
sentinel monitor mymaster 172.16.36.70 6379 2
sentinel parallel-syncs mymaster 3
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
启动服务
redis-sentinel /etc/redis-sentinel.conf
查看服务启动状态
users:(("master",2112,14))
[root@Centos7 ~]# ss -tln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:26379 *:*
操作主机: 172.16.36.76
# vim /etc/redis-sentinel.conf
port 26379
dir "/tmp"
daemonize yes
sentinel monitor mymaster 172.16.36.70 6379 2
sentinel parallel-syncs mymaster 3
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
启动服务
redis-sentinel /etc/redis-sentinel.conf
查看服务启动状态
users:(("master",2112,14))
[root@Centos7 ~]# ss -tln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:26379 *:*
查看sentinel相关的日志信息
tailf /var/log/redis/redis-sentinel.log
[32524] 25 Mar 10:05:02.290 # Sentinel runid is a44025e518b65c512340c48535df119496f7a0d8
[32524] 25 Mar 10:05:02.291 # +monitor master mymaster 172.16.36.70 6379 quorum 2
[32524] 25 Mar 10:05:32.322 # +sdown slave 172.16.36.71:6379 172.16.36.71 6379 @ mymaster 172.16.36.70 6379
[32524] 25 Mar 10:05:46.311 * +sentinel sentinel 172.16.36.76:26379 172.16.36.76 26379 @ mymaster 172.16.36.70 6379
[32524] 25 Mar 10:05:57.071 * +sentinel sentinel 172.16.36.75:26379 172.16.36.75 26379 @ mymaster 172.16.36.70 6379
[32524] 25 Mar 10:09:03.727 # +sdown master mymaster 172.16.36.70 6379
将当前的Master节点shudown,查看sentinel的相关日志信息
[32524] 25 Mar 10:09:03.747 # +new-epoch 4
[32524] 25 Mar 10:09:03.749 # +vote-for-leader 90c011868befc3047a8527886efce8f8c6f9ea34 4
[32524] 25 Mar 10:09:03.836 # +odown master mymaster 172.16.36.70 6379 #quorum 3/2
[32524] 25 Mar 10:09:03.836 # Next failover delay: I will not start a failover before Fri Mar 25 10:15:04 2016
[32524] 25 Mar 10:09:04.854 # +config-update-from sentinel 172.16.36.75:26379 172.16.36.75 26379 @ mymaster 172.16.36.70 6379
[32524] 25 Mar 10:09:04.854 # +switch-master mymaster 172.16.36.70 6379 172.16.36.72 6379
[32524] 25 Mar 10:09:04.855 * +slave slave 172.16.36.71:6379 172.16.36.71 6379 @ mymaster 172.16.36.72 6379
[32524] 25 Mar 10:09:04.856 * +slave slave 172.16.36.70:6379 172.16.36.70 6379 @ mymaster 172.16.36.72 6379
对当前主节点监控sentinel的活跃探测信息
root@Centos7 ~]# redis-cli -h 172.16.36.72
172.16.36.72:6379> monitor
OK
1458878723.052705 [0 172.16.36.76:53255] "PING"
1458878723.402835 [0 172.16.36.75:38413] "PING"
1458878723.586806 [0 172.16.36.74:32824] "PING"
1458878723.859748 [0 172.16.36.75:38413] "PUBLISH" "__sentinel__:hello" "172.16.36.75,26379,90c011868befc3047a8527886efce8f8c6f9ea34,4,mymaster,172.16.36.72,6379,4"
1458878724.099837 [0 172.16.36.76:53255] "PING"
1458878724.152776 [0 172.16.36.76:53255] "PUBLISH" "__sentinel__:hello" "172.16.36.76,26379,21a0a795010287138b6efc636d03edcce66bcd56,4,mymaster,172.16.36.72,6379,4"
1458878724.454214 [0 172.16.36.75:38413] "PING"
1458878724.617819 [0 172.16.36.74:32824] "PING"
1458878724.693888 [0 172.16.36.74:32824] "PUBLISH" "__sentinel__:hello" "172.16.36.74,26379,a44025e518b65c512340c48535df119496f7a0d8,4,mymaster,172.16.36.72,6379,4"
使用info sentinel命令查看主从信息
172.16.36.74:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=mymaster,status=ok,address=172.16.36.72:6379,slaves=2,sentinels=3
Redis Clustering
在redis3.0版本中引入clustering功能, 是去中心化的分布式数据库,通过分片机制进行数据分布,clustering内的每个节点仅有数据库一部分数据,每个节点都有全局元数据,通过查找元数据,即可查询到数据存放在哪台服务器
分布式解决方案
Twemproxy(Twitter)
- 代理分片机制
- 优点
- 非常稳定,企业方案
- 缺点
- 单点故障
- 需要依赖第三方软件,如Keeplived
- 无法平滑地横向扩展
- 没有后台界面
- 代理分片机制引入更多的来回次数并提高延迟
- 单核模式,无法充分利用多核,除非多实例
- Twitter官方肉串不再继续使用
Codis(豌豆荚)
- 代理分片机制
- 2014年11月开源
- 基于GO以及C语言开发
- 优点
- 非常稳定,企业级方案
- 数据自动平衡
- 高性能
- 简单的测试显示较Twemproxy快一倍
- 善用多核CPU
- 简单
- 没有paxos类的协调机制
- 没有主从复制
- 有后台界面
- 缺点
- 代理分片机制引入更多的来回次数并提高延迟
- 需要第三方软件支持协调机制
- 目前支持zookeeper及Etcd
- 不支持主从复制 ,需要另外实现
- Codis采用proxy方案,所有必然会带来单机性能的损失
- 经测试,在不开Pipeline的情况下,大概会损失40%左右的性能
Redis Cluster(官方)
- 官方实现
- 需要3.0或更高版本
- 优点
- 无中心的P2P Gossip分散式模式
- 更少的来回次数并降低延迟
- 自动于多个redis节点进行分片
- 不需要第三方软件支持协调机制
- 缺点
- 依赖于redis 3.0或更高版本
- 需要时间验证其稳定性
- 没有后台界面
- 需要智能客户端
- redis客户端必须支持redis cluster架构
- 较Codis有更多的维护升级版本