为了方便讲解,笔者在实操过程中全部使用的是默认配置。
配置方式选择
通过.conf文件配置(建议)
如果想自定义配置文件,可查看笔者的上一章中启动一节的描述。下面例子中是默认配置文件,修改后需重新启动redis服务。cd /usr/local/etc
vim redis.conf
运行交互命令配置
可以运行状态中动态修改一部分配置,下面只给出配置的方式,至于哪些配置可在运行中动态修改需要读者自行查询官方文档或用以下命令来查看,重新打开个终端窗口(命令行工具,笔者用的是mac系统自带的终端工具,但笔者比较推荐iTerm2工具);
//进入到安装目录中
cd /usr/local/Cellar/redis/6.2.6/bin
//执行命令,连接服务端
./redis-cli
//然后执行以下命令
config get param||set param
//查看所有配置
config get *
//查看指定的参数配置
config get loglevel
节点配置
因配置文件内容比较多,读者可自行查看/usr/local/etc/redis.conf文件,下面章节只描述一些重要配置参数的作用。读者可自行试验。
服务相关
以下参数只能由配置文件配置,不能在运行中修改
daemonize://是否以守护进程启动,默认值no
pidfile://线程pid,默认值为/var/run/redis
port://服务端口,默认值6397
databases://redis内部存储库的数据,默认值16
dir://指定快照和持久化文件存放的位置,默认值./
no_loose_disabled-commands://设置禁用的命令,多个命令通过逗号隔开,目前支持的命令如下:flushall, flushdb, keys, hgetall, eval, evalsha, script
rename -command oldcommand newcommmand://在配置文件中把一些flushall这样的命令重新命名成比较复杂的字段串
databases说明:一个逻辑分组,数据库间也不是物理隔离的,它更像一个命名空间。redis默认支持16个数据库,可以修改这个数字,redis不支持自定义数据库名,在开发时必须记住。在单机版开发时客户端可指定通过select命令连接指定的库,但需要注意有些命令是合局的,比如flushall。
在单机环境时当建立连接后,默认选择编号为0的数据库,可以通过select命令来选择,但集群环境只有一个库。所以这个配置只适用于单机环境。
快照相关
redis快照功能,是可以被关闭的,关闭后节省了磁盘空间,但在主宕机时也增大了丢数据的风险,所以一般不是非必要情况不要关闭快照功能,redis在以下三种情况下会创建快照:
- 通过bgsave, save,shutdown命令,其中save,shutdown这两个命令是阻塞的,其间不会接收用户请求,bgsave命令会新开一个线程,异步创建快照,其间不会阻塞用户请请求;
- 当有新节点加入时,主节点也会创建快照,主节点会先执行bgsave然后再sync同步;
- flushall命令,这个命令会清除数据库中的所有数据,但如果配置了快照功能则会先生成快照,再执行fluashall命令;
注:bgsave命令备份会新开一个线程,同时也占用了部分CPU资源,在极端情况下有造成机器停顿的风险,比如宿主机同时在运行大量的运算,另外bgsave的时间要比save长5倍左右,一般数据量1G大概会占用20ms左右时间来生成快照,有时为了平衡上述关系,对于不太重要的数据会关闭快照功能,转而采用定时任务或手动触发。
虽然bgsave有各种风险,但如果按CAP原则来设置的话,还是会选择服务的稳定性。一台服务器不行就扩两台,这也是大多数互联网公司在设计系统时如果资源与稳定性等方面发生冲突,都会花钱选择扩容的原因,毕竟资源还是很好解决的。下面是与快照相关的配置参数:
save:900 1, 300 10, 60 10000,
stop-writtes-on-bgsave-error no //
rdbcompression://默认值yes,快照是否进行压缩
rdbchecksum://默认值yes
dbfilename://默认值dump.rdb,存储在dir指定的目录下
save配置,触发的是bgsave命令,可以配置多个触发条件,这些条件是或的关系,用逗号分隔,redis会依次检查,只要满足前面的条件就不会再检查下一条规则是否满足了,默认配置解读如下:
- save 900 1: 如果超过每1秒有900个key发生变化(新增、修改和删除),则重写rdb文件;
- save 300 10: 如果每10秒有300个key发生变化(新增、修改和删除),则重写rdb文件;
- save 60 3600: 表示如果每60秒有10000个key发生变化(新增、修改和删除),则重写rdb文件。
增量文件
aof与rdb的区别和作用就不在细述了,可自行在网上查询,这里只提一点容易被忽略的内容,这个文件它缓存的是命令,命令会追加到AOF文件结尾。
appendonly://默认值no,开启AOF模式
appendfsync://默认值everysec每秒写入一次,
auto-aof-rewrite-percentage://默认值100,当前的AOF大小超过上次重写时的AOF大小的百分比时会再次进行重写,如果没重写过,则以启动时AOF文件大小为依据
auto-aof-rewrite-min-size: //默认值64mb,允许重写的最小AOF文件大小。
appendfsync配置:表示执行数据操作指令后,数据缓存到硬盘上的时间。不建议修改,可选值还有always和no,其中 no不代表不同步,只是同步的时间由系统决定(这个选项不太好评估,所以不建议使用),always表示实时同步,也不不建议用,因为会造成I/O放大,影响磁盘的寿命。
auto-aof-rewrite-percentage和auto-aof-rewrite-min-size配置:这两个配置一起使用的,默认配置表示当AOF文件大于64M时,并且AOF文件的体积比上一次重写之后的体积大了至少一倍(100%)时,才会执行gbrewriteaof命令,也可以人为用这个命令来控制AOF文件的备份。
主从相关
上面描述的的是单机配置,如果在高负载还需要多机,redis间采用的是主从复制(master-slave模式),不支持主主复制。但slave节点可以有自己的slave节点。
节点:分布式环境,会弱化服务器的概念,都会采用节点这个术语来描述,在多数分布式系统中不会存在混合部署的情况,所以可以认为节点==服务器或节点==容器。笔者在以后的文章里也都会采用节点这个术语。
在主从或从从复制时,master节点会先执行bgsave命令,然后将整个快照(rdb文件)发给slave节点,发送期间master会用缓存(aof文件)记录未在快照中的命令,当master发送完快照后,再发送缓存中的写命令给slave,同时slave节点处理快照时会丢弃自身原有的所有数据。
如果在同步期间又有新的slave节点接入,master节点不会重新生成快照,它会把当前的快照发送给所有的slave节点,如果之前同步完成了,则会再生成一个新快照重复之前同步过程。redis这种master-slave模式同步的最大问题在于多个slave节点连接时会造成大量的带宽被占用,因为master节点会持续创建快照然后传输。所以最好的方式是采用树状网络拓扑,即master-slave-slave这样的结构,同步的过程交给中间的slave节点来进行,定向更新。
masterauth://默认值yes
slave-serve-stale-data://默认值yes
slave-read-only://slave数据库的设置,默认值yes,如果no,从数据库也可以直接通过客户端写入数据,否则只接受master同步的数据
requirepass://为redis设置一个密码,因其性能高,为防止暴力猜密码尽量复杂。通过auth来发送密码,如果有从数据库时,需要在从数据库中设置masterauth参数。
maxmemory://设置可用的最大空间大小
maxmemory-policy://设置缓存满后Redis删除内容的策略。您可以在如下八种策略中进行选择,默认值volatile-lru
maxmemory-samples://默认值3
slaveof://ip:port(主服务器配置),可以通过slaveof命令来运行时配置,通过redis-cli连接不同的数据库,输入info replication来查看配置是否正确
性能相关
这个比较简单,多数是和数据存储方式相关,看一下下面的注释就可以理解了,后面章节会详细描述。
lua-time-limit://默认值5000
slowlog-log-slower-than://默认值10000,设置命令执行超过多长时间后加入到耗时命令日志,单位微秒,如值为0时关闭这个功能
slowlog-max-len://默认值128,耗时命令日志记录数
hash-max-ziplist-entries://默认值512,散列类型最大数量,其会影响数据存储是采用ziplist还是hashtable编码来存储数据
hash-max-ziplist-value://默认值64,字段名和字段值的长度,和上个参数一起会影响数据存储是采用ziplist还是hashtable编码来存储数据
list-max-ziplist-enries://默认值512
list-max-ziplist-value://默认值64
set-max-inset-entries://默认值512
zset-max-ziplist-entries://默认值128
zset-max-ziplist-value://默认值64
哨兵配置
集群环境中,加入了slave节点通过数据冗余的方式解决了和读写分离的问题,间接提升了redis的吞量(读),同时节点的健康度就需要特别注意了,如果需要人工介入的方式来监控基本不太可能,因此哨兵就是实现了这个自动化监控的功能。它的作用是监控master-slave节点是否正常运行以及master节点出现问题后自动将slave节点升级为master节点。
在集群环境中,可以用哨兵监控哨兵、也可以用一个哨兵监控多个master节点(需要配置多个下面第一条的配置)、还可以用多个哨兵监控一个主数据库。配置过程如下:
- 建立sentinel.conf文件,内容为sentinel monitor mymaster 127.0.0.1 6379 30000。mymaster表示主数据库名字,启动后会自动识别从数据库,所以不需要配置从数据库。后两个参数表示IP和PORT。30000表示执行故障恢复操作需要几个哨兵同意。
- 将上述.conf路径传递给sentinel进程。redid-sentinel /path/to/sentinel.conf
原理如下:部署成功后,哨兵会按sentinel down-after-milliseconds mymaster 30000中配置的时间周期地向master节点的__sentinel__:hello订阅请求的内容,同时发送info命令获取信息,每秒会向所有节点发送ping命令。当ping未回复则主观认为下线了,如果是master节点,还会向其它哨兵发送sentinel is-master-down-by-addr询问,如果达到指定的询问数量(上例中的30000),则认为客观下线了,这时就会执行故障恢复功能。一般时候不要部署单一和过多的哨兵,如果节点不是很多时尽量为每套master-slave节点配置一个哨兵。
建议的配置模式:slave也可以做为master来使用,这样就可以组建一个树状的redis群组。其使用场景如下:主数据库只写,从数据库只读操作。另一个耗时的操作是持久化,可以在slave中启用持久化,在master中禁用持久化。当master崩掉时可以在slave中启用slaveof no one提供为主数据,在master中使用slaveof变为从数据库,防止数据丢失。也可以同步数据回来。但这个功能不要做成自动重启,需要改动参数后再重启。
# mymaster定义一个master数据库的名称,后面是master的ip, port,1表示至少需要一个Sentinel进程同意才能将master判断为失效
# 如果不满足这个条件,则自动故障转移(failover)不会执行
sentinel monitor mymaster 127.0.0.1 6379 1
# master的密码
# sentinel auth-pass mymaster 123456
# 5s未回复PING,则认为master主观下线,默认为30s
sentinel down-after-milliseconds mymaster 5000
# 指定在执行故障转移时,最多可以有多少个slave实例在同步新的master实例,在slave实例较多的情况下
# 这个数字越小,同步的时间越长,完成故障转移所需的时间就越长
sentinel parallel-syncs mymaster 2
# 如果在该时间(ms)内未能完成故障转移操作,则认为故障转移失败,生产环境需要根据数据量设置该值
sentinel failover-timeout mymaster 300000
哨兵可以视为集群的子集,在不需要水平扩容的时候哨兵就够了,否则就要使用集群。前者的缺点是每个节点存储同样大的数据,势必造成资源的浪费,如果使用分片技术又存在很多问题。所以集群就是不二选择了。哨兵模式基于主从复制模式。哨兵模式下,master挂掉可以自动进行切换,系统可用性更高。缺点是同样也继承了主从模式难以在线扩容的缺点,Redis的容量受限于单机配置,需要额外的资源来启动sentinel进程,实现相对复杂一些。
集群配置
在这里大家一定要清楚一个概念,master-slave是用于数据备份保证数据不丢的情况下也可用于提高系统的吞吐量(读),集群是分布式中的一个概念,核心技术是分区,不具备保证数据不丢的功能,但可扩充系统的吞吐量(写)。
redis的集群原理如下,客户端与redis节点直连,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可,在Redis的每个节点上,都有一个插槽(slot),取值范围为0-16383 ,一共16384个槽。当我们存取key的时候,redis会根据CRC16的算法得出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
为了保证高可用,cluster模式也引入主从复制模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点都宕机了,那么该集群就无法再提供服务了。为了增加集群的可访问性,官方推荐的方案是将node配置成主从结构,即一个master主节点,挂n个slave从节点。这时,如果主节点失效,Redis Cluster会根据选举算法从slave节点中选择一个上升为主节点,整个集群继续对外提供服务,Redis Cluster本身提供了故障转移容错的能力,所以有时从节点作为备用节点,不提供请求,只作为故障转移使用。配置集群需要设置cluster-enabled选项为yes,集群中至少需要3台主数据库才能正常运行。配置如下:
- 配置cluster-enabled yes;集群会将当前节点记录的集群状态持久化到指定文件中,默认为当前工作目录下的nodes.conf。每个节点对应的文件必须不同,必须通过cluster-config-file来修改此文件的名字;
- 通过info cluster来查看节点信息,此时节点还是孤立的;
- redis提供了redis-trib.rb的RUBY程序配置集群,它依赖gem的redis包,通过gem install redis来安装;
- 执行命令:/path/to/redis-trib.rb create —replicas 1 127.0.0.1:6380 127.0.0.1:6381……(至少6个),—replicas 1表示每个主数据库拥有的从数据库的数量;
- 执行cluster nodes可以获得集群中所有节点的信息;
- 通过cluster meet ip port向集群中添加新节点;
- 分配插槽(插槽就是key和实例的对应关系,其实现规则可参考CRC16算法实现。redis集群会分为16384个插槽)。可以用cluster slots查看插槽的分配情况,在已连接的节点上用cluster addslots 100 101 102,重新分配插槽命令如下:/path/to/redis-trib.rb reshard ip:port。(通过cluster nodes)可以获取redis实例运行的ID;
- 如果一个至少负责一个插槽的主数据库下线且没有相应的从数据库可以进行故障恢复,则整个集群就认为下线了。可以通过修改cluster-require-full-coverage no为解决这个问题;