特点
<font color="grey">redis是高性能的key-value的数据库,其支持数据的持久化,可以将内存中的数据保存在磁盘中,重启时再次加载使用;具有丰富的数据类型支持,例如list, set, zset, hash等; 支持数据备份,也即master-slave模式的数据备份(注意备份和持久化的区别)。此外redis具备高性能的读写效率,操作具备原子性,意思就是要么执行成功要么失败完全不执行,单个操作是原子性的,多个操作也支持事务(通过MULTI和EXEC包裹起来)但要特别注意的是并非是原子性的,此外还支持发布/订阅,通知,key过期等特性</font>
介绍
<font color="grey">redis是一个字典结构的存储服务器,而实际上一个redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中,这与我们熟知的在一个关系数据库中可以创建多个数据库类似,所以可以将其中的每个字典都理解成为一个独立的数据库。每个数据库对外都是一个从0开始的递增的数字命名,redis默认支持16个数据库,可以通过配置databases来修改这一个数字,客户端与redis建立连接后会自动选择0号数据库,不过可以随时用select命令来切换数据库,例如选择1号数据库: select 1。这些以数字命名的数据库和我们平时理解的数据库有所区别,首先redis不支持数据库的自定义命名,每个数据库都是以编号命名,开发者必须自己记录哪些数据库存储了哪些数据,另外redis也不支持为每个数据库设置不同的访问密码,所以一个客户端要么可以访问所有的数据库,要么一个数据库也没有权限访问。最为重要的是多个数据库之间并不是完全隔离的,比如flushall命令可以清空一个redis实例中所有的数据库中的数据。综上所述,这些数据库更像是一种命名空间,而不适宜存储不同应用程序的数据,更应该使用不同的Redis实例来存储。由于redis非常轻量,一个空redis实例占用的内存只有1M左右,所以不用担心多个redis实例会额外占用很多内存。</font>
基础配置
redis配置文件为redis.conf,在安装目录下,在启动redis服务时需要指定配置文件,基础配置如下:
- daemonize
redis默认不是以守护进程的方式运行,使用yes启用守护进程
- port
指定redis的监听端口,默认端口为6379
- pidfile
当redis以守护进程的方式运行时,redis默认会把pid写入该项配置的路径下文件中,例如: pidfile /var/run/redis.pid
- bind
绑定的主机地址,一般不用设置。默认bind值为127.0.0.1,这样redis服务只能通过本机的客户端连接,而无法通过远程连接,这样可以避免将redis服务暴露于危险的网络环境中,防止一些不安全的人随随便便通过远程连接到redis服务。如果bind选项为空的话,那会接受所有来自于可用网络接口的连接;
- timeout
当客户端闲置多长时间后关闭连接,指定为0表示关闭该功能
- loglevel
指定日志的记录级别,总共支持四个级别:debug、verbose、notice、warning
- logfile(stdout)
日志记录方式,默认为标准输出,如果redis配置为守护进程,这里又配置为标准输出,则日志将会发送给/dev/null
- database(16)
设置数据库的数量,默认数据库为0
- save seconds changeNumber
指定在多长时间有多少次更新就将数据同步到数据文件,例如save 300 10
- rdbcompression
指定存储到本地数据库时是否压缩,默认为yes,如果为了节省cpu时间,可以关闭此项
- dbfilename
指定本地数据库的文件名字,默认值为dump.db
- dir
指定本地数据库存放目录
- slaveof masterip masterport
设置本机为slave服务时,要设置master服务的ip和端口,在redis启动时自动从master进行数据同步
- requirepass foobared
设置redis连接密码,在使用客户端连接redis服务时需要,注意该配置和masterauth的区别,设置密码后通过redis-cli -h ip -p port登录后,要首先通过auth password来进行密码校验
- masterauth master-password
当master服务设置了密码保护时,slave服务连接master服务的密码,这点特别重要在配置主从实例时,slave实例的配置在master实例配置有requirepass时一定要有masterauth,也就是说master实例的requirepass不仅仅对客户端生效,对于slave实例一样生效
- maxclients
设置同一时间的最大客户端连接数,默认无限制(maxclients 0),redis可以同时打开的客户端连接数为redis进程可以打开的最大文件描述符数,当客户端连接数到达限制时,redis会关闭新的连接并向客户端返回max number of client reached
- maxmemory
指定redis最大内存限制,启动时会把数据加载到内存中,达到最大限制后会尝试先清除已到期或者即将过期的key
- appendonly
指定是否在每次更新操作后进行日志记录,redis默认是异步把数据写入磁盘,如果不开启,可能会在断电时一段时间内的数据丢失,因为redis本身同步数据是按照上面的save条件来同步的,所以会有数据在一段时间内只存在于内存中。该选项默认值为no
- appendfilename
更新日志文件的文件名,默认为appendonly.aof
- appendfsync
指定日志的更新条件,共有三个值可用:everysec:表示每秒同步一次;always:每次更新后手动调用fsync将数据写到磁盘;no:表示等待操作系统进行数据缓存同步到磁盘
多实例(主从)
<font color="grey">启动redis服务可以通过redis-server redis.conf形式,但是单例redis存在的问题是服务的健壮性如何保证?redis的主从模式提供了一个较好的方案,主从模式下一个redis实例作为主机,其他实例作为备份机,主机和从机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机只支持与主机数据的同步和读取,也就是说客户端可以将数据写入主机,由主机自动同步数据到从机。主从模式很好的解决了数据的备份问题,并且主从服务数据几乎是一致的,因此可以将写入数据的命令发送给主机,而读取的操作命令发给从机,进而达到读写分离的目的。主从模式也是多实例模式,这里多个实例可以是单机(同ip不同port)的,也可以是集群。redis主从模式的配置可以理解为多个不同的redis实例通过一定的配置告知相互的主从关系,而前面已经介绍每个redis实例都会占用本机的一个端口,所以主从模式的配置点有两个:当前实例的端口号和当前实例是主机还是从机,是从机的话其ip和端口是什么,最重要的是从机的redis.conf配置中一定要配置slaveof masterip masterport和masterauth masterpassword(在主机配置了requirepass的情况下),然后多个实例启动的时候必须通过各自的配置文件来启动,例如redis-server 6379.conf、redis-server 6380.conf、 redis-server 6381.conf,这样就分别启动了三个实例。那么该如何校验主从关系是否建立呢,可以通过redis-cli -h host -p port的方式登录主机实例,然后通过info replication来查看主从节点的状态。如果主从配置有问题,要注意查看redis.log日志文件查找问题所在。假设6379为主机,那么我们在6379实例上写入的数据,6380和6381也都会存在,当然主从关系也可以通过命令行的方式设定,但主从模式是否存在一些问题呢?是的,很明显的两个问题就是: 不同实例可能使用了不同的ip和端口,我们往往将读写分配给不同的实例进行从而达到提高系统吞吐量的目的,但这也会造成使用上的不便,因为每个客户端连接redis实例的时候都指定了ip和端口号的,如果所连接的redis实例出现问题,主从模式没有提供一定的手段通知客户端另外可连接的实例地址,因而需要手动来更改;另外一个问题,主从模式下,如果主节点故障,那么从节点因为没有主节点而同步中断,因为也需要人工进行故障转移工作。综合来讲就是主从模式是很好的方案,但在实际运用上还需要考虑很多问题,redis 2.8版本后正式提供了sentinel架构可以很好的解决上述问题(sentinel架构解决的主要问题就是主从模式下节点的故障转移工作)。结合node来看主从模式和sentinel的关系是不是很类似于child_process和cluster的关系</font>
配置redis主从多实例时,redis.xx.conf涉及配置主要如下:
- pidfile /var/run/redis_6380.pid
- port 6380
- dbfilename dump6380.rdb
- slaveof ip port
- masterauth password(在主机配置了requirepass的情况下)
检查主从关系是否建立:redis-cli登录后,查看主从节点状态info replication
关于sentinel
<font color="grey">sentinel本意为哨兵,关于sentinel我们需要首先搞清楚几个概念: 主节点(redis主服务,一个独立的redis进程)、从节点(redis从服务,一个独立的redis进程)、sentinel节点(监控redis节点的一个独立的sentinel进程)、sentinel节点集合(若干sentinel节点进程)、应用方(泛指一个或多个客户端),redis-sentinel主要功能就是:不时监控redis是否按照预期良好地运行,如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);能够自动进行master slave的切换,当一个master节点不可用时,能够选举出一个从节点来作为新的master节点,其他的slave节点也会将自己追随的master的地址改为最新的;每个sentinel节点就是一个redis实例,与主从节点不同的是sentinel节点作用是监控redis数据节点的,而sentinel节点集合则表示监控一组主从redis实例多个sentinel监控节点的集合,比如有主节点master和从节点slave-1,slave-2,为了监控这三个节点,这里配置了sentinel-1,sentinel-2,sentinel-3。在主从节点和sentinel节点配置好之后,sentinel节点之间会相互发送消息,以检测sentinel节点是否正常工作,并且sentinel节点也会向主从节点发送消息以检测主从节点是否正常工作。前面提到过sentinel架构的主要工作是解决主从模式下主节点的故障转移工作的。如果主节点因故障下线,sentinel节点发送检测消息时在指定时间内是不会收到回复的,那么该sentinel节点就主观的认为该主节点已经下线,它会发送消息给其他sentinel节点,以询问其是否“认为”该主节点已经下线,其余sentinel节点收到消息后也会发送探测消息给主节点,如果认为该主节点下线,那么会回复向其询问的sentinel节点,告知其也认为该主节点已经下线。当N个sentinel节点回复说认为当前主节点已下线,那么就会进行主节点的故障转移工作,故障转移的基本思路是在从节点中选取某个节点向其发送slaveof no one(假设选取的节点为127.0.0.1 6380),使其成为新的主节点,然后sentinel向其余的节点发送slaveof 127.0.0.1 6380的命令使他们成为新的主节点的从节点。具体工作方式如下:</font>
- 每个sentinel以每秒钟一次的频率向它所知道的master,slave节点发送一个ping命令
- 如果一个实例距离最后一次有效回复ping命令时间超过down-after-millseconds选项所设定的值,则这个实例会被sentinel标记为主观下线
- 如果一个master被标记为主观下线,则正在监视这个master的所有sentinel要以每秒一次的频率确认master的确进入了主观下线状态
- 当有足够数量的sentinel认为master的确进入了主观下线状态,则master被标记为客观下线
- 在一般情况下,每个sentinel会以每10秒一次的频率向它已知道的master、slave发送info命令
- 当master被标记为客观下线时,sentinel向下线的master和slave发送info命令的频率会从10秒一次改为每秒一次
- 若没有足够数量的sentinel同意master已经下线,master的客观下线状态就会被移除
- 若master重新向sentinel的ping命令返回有效回复,master的主观下线状态就会被移除
<font color="grey">与配置redis主从实例一致,每个sentinel实例也有自己的配置文件(例如:sentinel.conf),具体配置如下:</font>
- port 26379
指定sentinel实例端口号
- daemonize yes
是否以守护进程方式启动
- logfile "26379.log"
- dir /opt/soft/redis/data
- sentinel monitor mymaster 127.0.0.1 6379 2
指定sentinel监视一个名称为mymaster的master(这里也定义了主节点的名称,注意在redis-sentinel客户端例如ioredis连接服务时需要用到的),master实例的地址为127.0.0.1,端口为6379,最后的2表示当有2个sentinel检测到master异常时才会判定其失效,也就是说只有当2个sentinel都判定了master失效才会自动进行故障迁移
- sentinel auth-pass master-name master-password
指定连接master和slave时的密码,注意的是sentinel不能分别为master和slave设置不同的密码,因此master和slave的密码应该设置相同。这里注意redis也不可以为同个实例的不同库设置不同密码
- sentinel down-after-milliseconds mymaster 30000
指定sentinel探测redis实例断线的时间,单位是毫秒
- sentinel parallel-syncs mymaster 1
指定执行故障转移时,最多可以有多少个slave同时对新的master进行同步,这个数据设置为1,虽然完成故障转移的时间会变长,但是可以保证一次只有1个slave处于不能处理命令请求的状态
- sentinel failover-timeout mymaster 180000
如果在多少秒内没有把宕掉的那台maser恢复,那哨兵就认为这是一次真正的宕机,而排除该宕机的master作为节点选取时可用的node,然后等待一定的设定值的毫秒数后再来探测该节点是否恢复;
- sentinel myid mm55d2d712b1f3f312b637f9b546f00cdcedc787
当启动过redis-sentinel时,会在主机sentinel.conf和从机sentinel.conf中生成myid,建议重启redis-sentinel时将两个sentinel.conf中生成的myid删除,不然主从切换时会根据myid去找对应的从机,当新生成的myid和原来的myid不一致将会导致无法切换。启动顺序是先启动主机redis-server,再启动从机redis-server,再启动主机redis-sentinel,在启动从机redis-sentinel; 对于多个sentinel节点配置时,配置文件基本一致,需要把端口号port修改为相应端口,这里注意sentinel monitor mymastername 127.0.0.1 6379 2这里的端口号是不用更改的,因为sentinel是通过检测主节点的状态来得知当前的主节点的从节点有哪些的。配置完成后我们首先分别启动redis主从节点,然后分别使用配置文件启动sentinel
<font color="grey">查看sentinel多实例状态: redis-cli登录sentinel节点后,通过info sentinel查看</font>
命令与连接
<font color="grey">在下载的redis安装包中通常含有redis客户端命令行工具,客户端基本语法为redis-cli,例如要到远程redis服务上执行指令: redis-cli -h host -p port -a password,如果redis服务实例配置需要密码登录,可以在上述指令后通过auth password的方式验证, 验证通过后我们可以通过ping指令来验证redis服务是否在运行中,然后可以通过select指令切换到指定数据库</font>
键
- set/get key (value)
- del key
- keys pattern
查找符合给定模式的key
- exists key
检查给定key是否存在
- type key
返回key所存储的值的类型
- expire key seconds
为指定key设置过期时间
脚本与事务
<font>redis脚本使用lua解释器来执行,另外redis支持事务可以一次执行多个命令,事务是以multi开始,然后将多个命令入列到事务中,最后以exec命令触发事务。在事务执行过程中,其他客户端提交的命令请求不会插入到事务执行命令序列中。redis单个命令的执行是原子性的,但要特别注意,Redis没有在事务上增加任何维持原子性的机制,所以redis事务的执行并不是原子性的,事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会导致后续未做指令不做,取消事务的指令为discard,该指令可以放弃执行事务块内的所有命令</font>
发布与订阅
redis发布与订阅是一种消息通信模式,发送者发布消息,订阅者接受消息,redis客户端可以订阅任意数量的频道,当有消息通过publish命令发送给频道channel时,这个消息就会被发送给订阅它的N个客户端,redis订阅和发布的命令分别为psubscribe channel和publish channel message
数据类型
-
字符串
set key value | get key | keys pattern | exists key
-
哈希
hash是一个string类型的field和value的映射表,hash特别适合存储对象
hset key field value | hmset key field1 value1 (field2 value2) | hget key field | hmget key field1 (field2) | hexists key field
-
列表
redis列表是简单的字符串列表,按照插入的顺序,可以添加一个元素到列表的头部或者尾部
lpush key value1 (value2) | lpop key | lindex key index | llen key | lrange key start stop | lset key index value .etc.
-
集合
redis集合是string类型的无序集合,集合成员是唯一的,不能出现重复数据 sadd key member | scard key | smembers key | sdiff key1 key2 | sinsert key1 key2 | sunion key1 key2 | spop key
客户端
- 可视化工具
- rdm(redis desktop manager)
- 多语言客户端组件
- node : ioredis | node_redis
- 命令行工具
- redis-cli -h host -p port -a password
连接池
sentinel如何保证主从的读写分离?
脑图
http://naotu.baidu.com/file/60238540368ac62bab19c39dc8e8ec5d?token=b76611586ad4e55b
来源:oschina
链接:https://my.oschina.net/u/4416864/blog/3625197