实验环境
LAP:10.6.191.208 redis_master:10.6.191.212 redis_slave:10.6.191.213
一、redis原理以及安装
1、redis原理
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis是一个key-value存储系统。
和Memcached缓存类似,Redis支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(有序集合)和hash(哈希类型)。
Redis是一种高级key-value数据库,它跟memcached类似,不过Redis的数据可以持久化,而且支持的数据类型很丰富,有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能。Redis也被看成是一个数据结构服务器。
Redis很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。Redis提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,方便易用,得到IT人的青睐。
Redis支持主从同步,数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制,由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录,同步对读取操作的可扩展性和数据冗余很有帮助。
目前使用Redis的互联网企业有:京东、百度、腾讯、阿里巴巴、新浪、图吧、研修网等等,如表12-1所示,为目前主流数据库简单功能对比:
名称 |
数据库类型 |
数据存储选项 |
操作类型 |
备注 |
Redis |
内存存储,Nosql数据库 |
支持字符串、列表、集合、散列表、有序集合 |
增、删、修改、更新 |
支持分布式集群、主从同步及高可用、单线程 |
Memcached |
内存缓存数据库,键值对 |
键值之间的映射 |
增、删、修改、更新 |
支持多线程 |
MySQL |
典型关系数据库,RDBMS |
数据库由多表主成,每张表包含多行 |
增、删、修改、更新 |
支持ACID性质 |
PostgreSQL |
典型关系数据库,RDBMS |
数据库由多表主成,每张表包含多行 |
增、删、修改、更新 |
支持ACID性质 |
MongoDB |
硬盘存储,Nosql数据库 |
数据库包含多个表 |
增、删、修改、更新 |
主从复制,分片,副本集、空间索引 |
2、redis部署安装
wget -c http://download.redis.io/releases/redis-4.0.12.tar.gz tar -zxf redis-4.0.12.tar.gz cd redis-4.0.12 make PREFIX=/usr/local/redis MALLOC=libc install cp redis.conf /usr/local/redis echo "export PATH=/usr/local/redis/bin:$PATH" >> /etc/profile source /etc/profile sed -i -e '/^bind/s/127.0.0.1/0.0.0.0/g' -e '/^daemonize/s/no/yes/g' /usr/local/redis/redis.conf /usr/local/redis/bin/redis-server /usr/local/redis/redis.conf
3、Redis配置文件详解
Redis是一个内存数据库,附Redis.conf常用参数的详解,后面章节会继续深入讲解。
daemonize yes # 当运行多个 redis 服务时,需要指定不同的pid文件和端口 pidfile /var/run/redis_6379.pid # 指定redis运行的端口,默认是 6379 port 6379 # 在高并发的环境中,为避免慢客户端的连接问题,需要设置一个高速后台日志 tcp-backlog 511 # 指定redis只接收来自于该 IP 地址的请求,如果不进行设置,那么将处理所有请求 # bind 192.168.1.100 10.0.0.1 # bind 127.0.0.1 #设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接; timeout 0 # 在Linux 上,指定值(秒)用于发送 ACKs 的时间。注意关闭连接需要双倍的时间。默认为 0 。 tcp-keepalive 0 # Redis总共支持四个日志级别: debug 、 verbose 、 notice 、 warning ,默认为 verbose # debug 记录很多信息,用于开发和测试 # varbose 有用的信息,不像 debug 会记录那么多 # notice 普通的 verbose ,常用于生产环境 # warning 只有非常重要或者严重的信息会记录到日志 loglevel notice #配置 log 文件地址 #默认值为 stdout ,标准输出,若后台模式会输出到 /dev/null 。 logfile /var/log/redis/redis.log #可用数据库数 #默认值为16 ,默认数据库为0,数据库范围在 0- ( database-1 )之间 databases 16 #数据写入磁盘快照设置 #保存数据到磁盘,格式如下 : #save <seconds> <changes> #指出在多长时间内,有多少次更新操作,就将数据同步到数据文件 rdb 。 #相当于条件触发抓取快照,这个可以多个条件配合 #比如默认配置文件中的设置,就设置了三个条件 #save 900 1 900 秒内至少有 1 个 key 被改变 #save 300 10 300 秒内至少有 300 个 key 被改变 #save 60 10000 60 秒内至少有 10000 个 key 被改变 # save 900 1 # save 300 10 # save 60 10000 # 后台存储错误停止写。 stop-writes-on-bgsave-error yes # 存储至本地数据库时(持久化到 rdb 文件)是否压缩数据,默认为 yes rdbcompression yes # 本地持久化数据库文件名,默认值为 dump.rdb dbfilename dump.rdb # 工作目录 # 数据库镜像备份的文件放置的路径。 # 这里的路径跟文件名要分开配置是因为 redis 在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成, # 再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。 # AOF 文件也会存放在这个目录下面 # 注意这里必须制定一个目录而不是文件 dir /var/lib/redis/ ################################# 复制 ################################# # 主从复制 . 设置该数据库为其他数据库的从数据库 . # 设置当本机为 slav 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 # slaveof <masterip><masterport> # 当 master 服务设置了密码保护时 ( 用 requirepass 制定的密码 ) # slave 服务连接 master 的密码 # masterauth <master-password> # 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式: # 1) 如果 slave-serve-stale-data 设置为 yes( 默认设置 ) ,从库会继续响应客户端的请求 # 2) 如果 slave-serve-stale-data 是指为 no ,出去 INFO 和 SLAVOF 命令之外的任何请求都会返回一个 # 错误 "SYNC with master in progress" slave-serve-stale-data yes # 配置 slave 实例是否接受写。写 slave 对存储短暂数据(在同 master 数据同步后可以很容易地被删除)是有用的,但未配置的情况下,客户端写可能会发送问题。 # 从 Redis2.6 后,默认 slave 为 read-only slaveread-only yes # 从库会按照一个时间间隔向主库发送 PINGs. 可以通过 repl-ping-slave-period 设置这个时间间隔,默认是 10 秒 # repl-ping-slave-period 10 # repl-timeout 设置主库批量数据传输时间或者 ping 回复时间间隔,默认值是 60 秒 # 一定要确保 repl-timeout 大于 repl-ping-slave-period # repl-timeout 60 # 在 slave socket 的 SYNC 后禁用 TCP_NODELAY # 如果选择“ yes ” ,Redis 将使用一个较小的数字 TCP 数据包和更少的带宽将数据发送到 slave , 但是这可能导致数据发送到 slave 端会有延迟 , 如果是 Linux kernel 的默认配置,会达到 40 毫秒 . # 如果选择 "no" ,则发送数据到 slave 端的延迟会降低,但将使用更多的带宽用于复制 . repl-disable-tcp-nodelay no # 设置复制的后台日志大小。 # 复制的后台日志越大, slave 断开连接及后来可能执行部分复制花的时间就越长。 # 后台日志在至少有一个 slave 连接时,仅仅分配一次。 # repl-backlog-size 1mb # 在 master 不再连接 slave 后,后台日志将被释放。下面的配置定义从最后一个 slave 断开连接后需要释放的时间(秒)。 # 0 意味着从不释放后台日志 # repl-backlog-ttl 3600 # 如果 master 不能再正常工作,那么会在多个 slave 中,选择优先值最小的一个 slave 提升为 master ,优先值为 0 表示不能提升为 master 。 slave-priority 100 # 如果少于 N 个 slave 连接,且延迟时间 <=M 秒,则 master 可配置停止接受写操作。 # 例如需要至少 3 个 slave 连接,且延迟 <=10 秒的配置: # min-slaves-to-write 3 # min-slaves-max-lag 10 # 设置 0 为禁用 # 默认 min-slaves-to-write 为 0 (禁用), min-slaves-max-lag 为 10 ################################## 安全 ################################### # 设置客户端连接后进行任何其他指定前需要使用的密码。 # 警告:因为 redis 速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行 150K 次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解 # requirepass jfedu # 命令重命名 . # 在一个共享环境下可以重命名相对危险的命令。比如把 CONFIG 重名为一个不容易猜测的字符。 # 举例 : # rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 # 如果想删除一个命令,直接把它重命名为一个空字符 "" 即可,如下: # rename-command CONFIG "" ###################################约束################################### #设置同一时间最大客户端连接数,默认无限制, #Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数, #如果设置 maxclients 0 ,表示不作限制。 #当客户端连接数到达限制时, Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息 # maxclients 10000 # 指定 Redis 最大内存限制, Redis 在启动时会把数据加载到内存中,达到最大内存后, Redis 会按照清除策略尝试清除已到期的 Key # 如果 Redis 依照策略清除后无法提供足够空间,或者策略设置为 ”noeviction” ,则使用更多空间的命令将会报错,例如 SET, LPUSH 等。但仍然可以进行读取操作 # 注意: Redis 新的 vm 机制,会把 Key 存放内存, Value 会存放在 swap 区 # 该选项对 LRU 策略很有用。 # maxmemory 的设置比较适合于把 redis 当作于类似 memcached 的缓存来使用,而不适合当做一个真实的 DB 。 # 当把 Redis 当做一个真实的数据库使用的时候,内存使用将是一个很大的开销 # maxmemory <bytes> # 当内存达到最大值的时候 Redis 会选择删除哪些数据?有五种方式可供选择 # volatile-lru -> 利用 LRU 算法移除设置过过期时间的 key (LRU: 最近使用 Least RecentlyUsed ) # allkeys-lru -> 利用 LRU 算法移除任何 key # volatile-random -> 移除设置过过期时间的随机 key # allkeys->random -> remove a randomkey, any key # volatile-ttl -> 移除即将过期的 key(minor TTL) # noeviction -> 不移除任何可以,只是返回一个写错误 # 注意:对于上面的策略,如果没有合适的 key 可以移除,当写的时候 Redis 会返回一个错误 # 默认是 : volatile-lru # maxmemory-policy volatile-lru # LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法 ( 为了节省内存 ) ,随意你可以选择样本大小进行检测。 # Redis 默认的灰选择 3 个样本进行检测,你可以通过 maxmemory-samples 进行设置 # maxmemory-samples 3 ############################## AOF############################### # 默认情况下, redis 会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失。 # 所以 redis 提供了另外一种更加高效的数据库备份及灾难恢复方式。 # 开启 append only 模式之后, redis 会把所接收到的每一次写操作请求都追加到 appendonly.aof 文件中,当 redis 重新启动时,会从该文件恢复出之前的状态。 # 但是这样会造成 appendonly.aof 文件过大,所以 redis 还支持了 BGREWRITEAOF 指令,对 appendonly.aof 进行重新整理。 # 你可以同时开启 asynchronous dumps 和 AOF appendonly no # AOF 文件名称 ( 默认 : "appendonly.aof") # appendfilename appendonly.aof # Redis 支持三种同步 AOF 文件的策略 : # no: 不进行同步,系统去操作 . Faster. # always: always 表示每次有写操作都进行同步 . Slow, Safest. # everysec: 表示对写操作进行累积,每秒同步一次 . Compromise. # 默认是 "everysec" ,按照速度和安全折中这是最好的。 # 如果想让 Redis 能更高效的运行,你也可以设置为 "no" ,让操作系统决定什么时候去执行 # 或者相反想让数据更安全你也可以设置为 "always" # 如果不确定就用 "everysec". # appendfsync always appendfsync everysec # appendfsync no # AOF 策略设置为 always 或者 everysec 时,后台处理进程 ( 后台保存或者 AOF 日志重写 ) 会执行大量的 I/O 操作 # 在某些 Linux 配置中会阻止过长的 fsync() 请求。注意现在没有任何修复,即使 fsync 在另外一个线程进行处理 # 为了减缓这个问题,可以设置下面这个参数 no-appendfsync-on-rewrite no-appendfsync-on-rewrite no # AOF 自动重写 # 当 AOF 文件增长到一定大小的时候 Redis 能够调用 BGREWRITEAOF 对日志文件进行重写 # 它是这样工作的: Redis 会记住上次进行些日志后文件的大小 ( 如果从开机以来还没进行过重写,那日子大小在开机的时候确定 ) # 基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动 # 同时需要指定一个最小大小用于 AOF 重写,这个用于阻止即使文件很小但是增长幅度很大也去重写 AOF 文件的情况 # 设置 percentage 为 0 就关闭这个特性 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ######## # LUA SCRIPTING ######### # 一个 Lua 脚本最长的执行时间为 5000 毫秒( 5 秒),如果为 0 或负数表示无限执行时间。 lua-time-limit 5000 ################################LOW LOG################################ # Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括 I/O 计算比如连接客户端,返回结果等,只是命令执行时间 # 可以通过两个参数设置 slow log :一个是告诉 Redis 执行超过多少时间被记录的参数 slowlog-log-slower-than( 微妙 ) , # 另一个是 slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除 # 下面的时间以微妙为单位,因此 1000000 代表一秒。 # 注意指定一个负数将关闭慢日志,而设置为 0 将强制每个命令都会记录 slowlog-log-slower-than 10000 # 对日志长度没有限制,只是要注意它会消耗内存 # 可以通过 SLOWLOG RESET 回收被慢日志消耗的内存 # 推荐使用默认值 128 ,当慢日志超过 128 时,最先进入队列的记录会被踢出 slowlog-max-len 128
4、Redis常用配置命令
Redis缓存服务器命令行中常用命令如下:
Redis CONFIG 命令格式如下: redis 127.0.0.1:6379> CONFIG GET|SET CONFIG_SETTING_NAME CONFIG GET * 获取Redis服务器所有配置信息; CONFIG SET loglevel "notice" 设置Redis服务器日志级别; CONFIG SET requirepass "jfedu" AUTH jfedu redis-cli -h host -p port -a password 远程连接redis数据库; CLIENT GETNAME 获取连接的名称; CLIENT SETNAME 设置当前连接的名称; CLUSTER SLOTS 获取集群节点的映射数组; COMMAND 获取Redis命令详情数组; COMMAND COUNT 获取 Redis 命令总数; COMMAND GETKEYS 获取给定命令的所有键; TIME 返回当前服务器时间; CONFIG GET parameter 获取指定配置参数的值; CONFIG SET parameter value 修改redis 配置参数,无需重启; CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据; DBSIZE 返回当前数据库的 key 的数量; DEBUG OBJECT key 获取 key 的调试信息; DEBUG SEGFAULT 让Redis服务崩溃; FLUSHALL 删除所有数据库的所有key; FLUSHDB 删除当前数据库的所有key; ROLE 返回主从实例所属的角色; SAVE 异步保存数据到硬盘; SHUTDOWN 异步保存数据到硬盘,并关闭服务器; SLOWLOG 管理 redis 的慢日志; SET keys values 设置key为jfedu,值为123; DEL jfedu 删除key及值; INFO CPU 查看服务器CPU占用信息; KEYS jfedu 查看是存在jfedu的key; KEYS * 查看Redis所有的KEY; CONFIG REWRITE 启动 Redis时所指定的redis.conf 配置文件进行改写; INFO [section] 获取Redis服务器的各种信息和统计数值; SYNC 用于复制功能(replication)的内部命令; SLAVEOF host port 指定服务器的从属服务器(slave server); MONITOR 实时打印出Redis服务器接收到的命令,调试用; LASTSAVE 返回最近一次Redis成功将数据保存到磁盘上的时间;; CLIENT PAUSE timeout 指定时间内终止运行来自客户端的命令; BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作; BGSAVE 后台异步保存当前数据库的数据到磁盘。
5、redis主从复制
为了提升redis高可用性,我们除了备份redis dump数据之外,还需要创建redis主从架构,可以利用从将数据库持久化(数据持久化通俗讲就是把数据保存到磁盘上,保证不会因为断电等因素丢失数据。
Redis需要经常将内存中的数据同步到磁盘来保证持久化。redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。)
Redis主从复制,当用户往Master端写入数据时,通过Redis Sync机制将数据文件发送至Slave,Slave也会执行相同的操作确保数据一致;且实现Redis的主从复制非常简单。同时slave上还可以开启二级slave,三级slave从库,跟MySQL的主从类似。
Redis主从配置非常简单,只需要在Redis丛库10.6.191.213配置中设置如下指令,slaveof表示指定主库的IP,10.6.191.212为master服务器,6379为master服务器Redis端口,配置方法如下:
10.6.191.212 Redis主库redis.conf配置文件如下:
daemonize yes pidfile /var/run/redis.pid port 6379 tcp-backlog 511 timeout 0 tcp-keepalive 0 loglevel notice logfile "" databases 16 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename redis.rdb dir /data/redis/ slave-serve-stale-data yes slave-read-only yes repl-disable-tcp-nodelay no slave-priority 100 appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 aof-rewrite-incremental-fsync yes
10.6.191.213 Redis丛库redis.conf配置文件如下:
daemonize yes pidfile /var/run/redis.pid port 6379 slaveof 10.6.191.212 6379 tcp-backlog 511 timeout 0 tcp-keepalive 0 loglevel notice logfile "" databases 16 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename redis.rdb dir /data/redis/ slave-serve-stale-data yes slave-read-only yes repl-disable-tcp-nodelay no slave-priority 100 appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 aof-rewrite-incremental-fsync yes
6、Redis数据备份与恢复
Redis所有数据都是保存在内存中,Redis数据备份可以定期的通过异步方式保存到磁盘上,该方式称为半持久化模式,如果每一次数据变化都写入aof文件里面,则称为全持久化模式。同时还可以基于Redis主从复制实现Redis备份与恢复。
1)半持久化RDB模式
半持久化RDB模式也是Redis备份默认方式,是通过快照(snapshotting)完成的,当符合在Redis.conf配置文件中设置的条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上,完成数据备份。
Redis进行RDB快照的条件由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。在配置文件中已经预置了3个条件:
save 900 1 #900秒内有至少1个键被更改则进行快照; save 300 10 #300秒内有至少10个键被更改则进行快照; save 60 10000 #60秒内有至少10000个键被更改则进行快照。
默认可以存在多个条件,条件之间是“或”的关系,只要满足其中一个条件,就会进行快照。 如果想要禁用自动快照,只需要将所有的save参数删除即可。Redis默认会将快照文件存储在Redis数据目录,默认文件名为:dump.rdb文件,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。也可以在Redis命令行执行config get dir获取Redis数据保存路径,如图所示:
Redis实现快照的过程,Redis使用fork函数复制一份当前进程(父进程)的副本(子进程),父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件,当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
执行fork的时操作系统会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时,操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我们可以通过定时备份RDB文件来实 现Redis数据库备份。
RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。除了自动快照,还可以手动发送SAVE和BGSAVE命令让Redis执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过fork子进程进行快照操作。
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存,根据数据量大小与结构和服务器性能不同,通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需花费20~30秒钟。
通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。此时需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。
2)全持久化AOF模式
如果数据很重要无法承受任何损失,可以考虑使用AOF方式进行持久化,默认Redis没有开启AOF(append only file)方式的全持久化模式。
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些,开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改该名称。
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少,可以在redis.conf中通过appendonly参数开启Redis AOF全持久化模式:
appendonly yes appendfilename appendonly.aof auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb appendfsync always #appendfsync everysec #appendfsync no
Redis AOF持久化参数配置详解:
appendonly yes #开启AOF持久化功能; appendfilename appendonly.aof #AOF持久化保存文件名; appendfsync always #每次执行写入都会执行同步,最安全也最慢; #appendfsync everysec #每秒执行一次同步操作; #appendfsync no #不主动进行同步操作,而是完全交由操作系统来做,每30秒一次,最快也最不安全; auto-aof-rewrite-percentage 100 #当AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据; auto-aof-rewrite-min-size 64mb #允许重写的最小AOF文件大小配置写入AOF文件后,要求系统刷新硬盘缓存的机制。
二、redis集群
1、Redis 集群简介
Redis 是一个开源的 key-value 存储系统,由于出众的性能,大部分互联网企业都用来做服务器端缓存。Redis 在3.0版本前只支持单实例模式,虽然支持主从模式、哨兵模式部署来解决单点故障,但是现在互联网企业动辄大几百G的数据,可完全是没法满足业务的需求,所以,Redis 在 3.0 版本以后就推出了集群模式。
Redis 集群采用了P2P的模式,完全去中心化。Redis 把所有的 Key 分成了 16384 个 slot,每个 Redis 实例负责其中一部分 slot 。集群中的所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新。
Redis 客户端可以在任意一个 Redis 实例发出请求,如果所需数据不在该实例中,通过重定向命令引导客户端访问所需的实例。
Redis集群提供一种方式自动将数据分布在多个Redis节点上。
Redis Cluster provides a way to run a Redis installation where data is automatically sharded across multiple Redis nodes.
2、Redis集群TCP端口(Redis Cluster TCP ports)
每个Redis集群中的节点都需要打开两个TCP连接。一个连接用于正常的给Client提供服务,比如6379,还有一个额外的端口(通过在这个端口号上加10000)作为数据端口,比如16379。第二个端口(本例中就是16379)用于集群总线,这是一个用二进制协议的点对点通信信道。这个集群总线(Cluster bus)用于节点的失败侦测、配置更新、故障转移授权,等等。客户端从来都不应该尝试和这些集群总线端口通信,它们只应该和正常的Redis命令端口进行通信。注意,确保在你的防火墙中开放着两个端口,否则,Redis集群节点之间将无法通信。
命令端口和集群总线端口的偏移量总是10000。
注意,如果想要集群按照你想的那样工作,那么集群中的每个节点应该:
- 正常的客户端通信端口(通常是6379)用于和所有可到达集群的所有客户端通信
- 集群总线端口(the client port + 10000)必须对所有的其它节点是可到达的
也就是,要想集群正常工作,集群中的每个节点需要做到以下两点:
- 正常的客户端通信端口(通常是6379)必须对所有的客户端都开放,换言之,所有的客户端都可以访问
- 集群总线端口(客户端通信端口 + 10000)必须对集群中的其它节点开放,换言之,其它任意节点都可以访问
如果你没有开放TCP端口,你的集群可能不会像你期望的那样工作。集群总线用一个不同的二进制协议通信,用于节点之间的数据交换
3、Redis集群数据分片(Redis Cluster data sharding)
Redis集群不同一致性哈希,它用一种不同的分片形式,在这种形式中,每个key都是一个概念性(hash slot)的一部分。
There are 16384 hash slots in Redis Cluster, and to compute what is the hash slot of a given key, we simply take the CRC16 of the key modulo 16384.
Redis集群中有16384个hash slots,为了计算给定的key应该在哪个hash slot上,我们简单地用这个key的CRC16值来对16384取模。(即:key的CRC16 % 16384)
Every node in a Redis Cluster is responsible for a subset of the hash slots
Redis集群中的每个节点负责一部分hash slots,假设你的集群有3个节点,那么:
- Node A contains hash slots from 0 to 5500
- Node B contains hash slots from 5501 to 11000
- Node C contains hash slots from 11001 to 16383
允许添加和删除集群节点。比如,如果你想增加一个新的节点D,那么久需要从A、B、C节点上删除一些hash slot给到D。同样地,如果你想从集群中删除节点A,那么会将A上面的hash slots移动到B和C,当节点A上是空的时候就可以将其从集群中完全删除。
因为将hash slots从一个节点移动到另一个节点并不需要停止其它的操作,添加、删除节点以及更改节点所维护的hash slots的百分比都不需要任何停机时间。也就是说,移动hash slots是并行的,移动hash slots不会影响其它操作。
Redis支持多个key操作,只要这些key在一个单个命令中执行(或者一个事务,或者Lua脚本执行),那么它们就属于相同的hash slot。你也可以用hash tags俩强制多个key都在相同的hash slot中。
4、Redis集群主从模式(Redis Cluster master-slave model)
In order to remain available when a subset of master nodes are failing or are not able to communicate with the majority of nodes, Redis Cluster uses a master-slave model where every hash slot has from 1 (the master itself) to N replicas (N-1 additional slaves nodes).
当部分master节点失败了,或者不能够和大多数节点通信的时候,为了保持可用,Redis集群用一个master-slave模式,这样的话每个hash slot就有1到N个副本。
在我们的例子中,集群有A、B、C三个节点,如果节点B失败了,那么5501-11000之间的hash slot将无法提供服务。然而,当我们给每个master节点添加一个slave节点以后,我们的集群最终会变成由A、B、C三个master节点和A1、B1、C1三个slave节点组成,这个时候如果B失败了,系统仍然可用。节点B1是B的副本,如果B失败了,集群会将B1提升为新的master,从而继续提供服务。然而,如果B和B1同时失败了,那么整个集群将不可用。
5、Redis集群一致性保证(Redis Cluster consistency guarantees)
Redis Cluster is not able to guarantee strong consistency. In practical terms this means that under certain conditions it is possible that Redis Cluster will lose writes that were acknowledged by the system to the client.
Redis集群不能保证强一致性。换句话说,Redis集群可能会丢失一些写操作。The first reason why Redis Cluster can lose writes is because it uses asynchronous replication.
Redis集群可能丢失写的第一个原因是因为它用异步复制。
写可能是这样发生的:
- 客户端写到master B
- master B回复客户端OK
- master B将这个写操作广播给它的slaves B1、B2、B3
正如你看到的那样,B没有等到B1、B2、B3确认就回复客户端了,也就是说,B在回复客户端之前没有等待B1、B2、B3的确认,这对应Redis来说是一个潜在的风险。所以,如果客户端写了一些东西,B也确认了这个写操作,但是在它将这个写操作发给它的slaves之前它宕机了,随后其中一个slave(没有收到这个写命令)可能被提升为新的master,于是这个写操作就永远丢失了。
这和大多数配置为每秒刷新一次数据到磁盘的情况是一样的。你可以通过强制数据库在回复客户端以前刷新数据,但是这样做的结果会导致性能很低,这就相当于同步复制了。
基本上,需要在性能和一致性之间做一个权衡。
如果绝对需要的话,Redis集群也是支持同步写的,这是通过WAIT命令实现的,这使得丢失写的可能性大大降低。然而,需要注意的是,Redis集群没有实现强一致性,即使用同步复制,因为总是有更复杂的失败场景使得一个没有接受到这个写操作的slave当选为新的master。(however note that Redis Cluster does not implement strong consistency even when synchronous replication is used: it is always possible under more complex failure scenarios that a slave that was not able to receive the write is elected as master.)
另一个值得注意的场景,即Redis集群将会丢失写操作,这发生在一个网络分区中,在这个分区中,客户端与少数实例(包括至少一个主机)隔离。
假设这样一个例子,有一个集群有6个节点,分别由A、B、C、A1、B1、C1组成,三个masters三个slaves,有一个客户端我们叫Z1。在分区发生以后,可能分区的一边是A、C、A1、B1、C1,另一边有B和Z1。此时,Z1仍然可用写数据到B,如果网络分区的时间很短,那么集群可能继续正常工作,而如果分区的时间足够长以至于B1在多的那一边被提升为master,那么这个时候Z1写到B上的数据就会丢失。
什么意思呢?简单的来说就是,本来三主三从在一个网络分区中,突然网络分区发生,于是一边是A、C、A1、B1、C1,另一边是B和Z1,这时候Z1往B中写数据,于此同时另一边(即A、C、A1、B1、C1)认为B已经挂了,于是将B1提升为master,当分区回复的时候,由于B1变成了master,所以B就成了slave,于是B就要丢弃它自己原有的数据而从B1那里同步数据,于是乎先去Z1写到B的数据就丢失了。
注意,有一个最大窗口,这是Z1能够向B写的最大数量:如果时间足够的话,分区的多数的那一边已经选举完成,选择一个slave成为master,此时,所有在少数的那一边的master节点将停止接受写。
也就说说,有一个最大窗口的设置项,它决定了Z1在那种情况下能够向B发送多数写操作:如果分隔的时间足够长,多数的那边已经选举slave成为新的master,此后少数那边的所有master节点将不再接受写操作。
在Redis集群中,这个时间数量是一个非常重要的配置指令,它被称为node timeout。在超过node timeout以后,一个master节点被认为已经失败了,并且选择它的一个副本接替master。类似地,如果在过了node timeout时间以后,没有一个master能够和其它大多数的master通信,那么整个集群都将停止接受写操作。
After node timeout has elapsed, a master node is considered to be failing, and can be replaced by one of its replicas. Similarly after node timeout has elapsed without a master node to be able to sense the majority of the other master nodes, it enters an error state and stops accepting writes.
6、Redis集群配置参数(Redis Cluster configuration parameters)
- cluster-enabled <yes/no>: 如果是yes,表示启用集群,否则以单例模式启动
- cluster-config-file <filename>: 可选,这不是一个用户可编辑的配置文件,这个文件是Redis集群节点自动持久化每次配置的改变,为了在启动的时候重新读取它。
- cluster-node-timeout <milliseconds>: 超时时间,集群节点不可用的最大时间。如果一个master节点不可到达超过了指定时间,则认为它失败了。注意,每一个在指定时间内不能到达大多数master节点的节点将停止接受查询请求。
- cluster-slave-validity-factor <factor>: 如果设置为0,则一个slave将总是尝试故障转移一个master。如果设置为一个正数,那么最大失去连接的时间是node timeout乘以这个factor。
- cluster-migration-barrier <count>: 一个master和slave保持连接的最小数量(即:最少与多少个slave保持连接),也就是说至少与其它多少slave保持连接的slave才有资格成为master。
- cluster-require-full-coverage <yes/no>: 如果设置为yes,这也是默认值,如果key space没有达到百分之多少时停止接受写请求。如果设置为no,将仍然接受查询请求,即使它只是请求部分key。
7、Redis 高可用集群搭建
安装部署任何一个应用其实都很简单,只要安装步骤一步一步来就行了。下面说一下 Redis 集群搭建规划,由于集群至少需要6个节点(3主3从模式),所以,没有这么多机器给我玩,我本地也起不了那么多虚拟机(电脑太烂),现在计划是在一台机器上模拟一个集群,当然,这和生产环境的集群搭建没本质区别。
我现在就要在已经有安装了 Redis 的一个 CentOS 下开始进行集群搭建。wget -c http://download.redis.io/releases/redis-4.0.12.tar.gz
tar -zxf redis-4.0.12.tar.gz cd redis-4.0.12 make PREFIX=/usr/local/redis MALLOC=libc install cp redis.conf /usr/local/redis
echo "export PATH=/usr/local/redis/bin:$PATH" >> /etc/profile
source /etc/profile
1)我们计划集群中 Redis 节点的端口号为 9001-9006
,端口号即集群下各实例文件夹。数据存放在 端口号/data
文件夹中。
mkdir -p /usr/local/redis-cluster/900{1,2,3,4,5,6}
2)复制一个配置文件并修改一下内容:
cp /usr/src/redis-4.0.12/redis.conf /usr/local/redis-cluster/9001
修改模板配置文件,vim 9001/redis.conf
port 9001(每个节点的端口号) daemonize yes bind 172.17.245.146(绑定当前机器 IP) dir /usr/local/redis-cluster/9001/data/(数据文件存放位置) pidfile /var/run/redis_9001.pid(pid 9001和port要对应) cluster-enabled yes(启动集群模式) cluster-config-file nodes9001.conf(9001和port要对应,每个配置文件都需要修改,不然无法启动所有实例) cluster-node-timeout 15000 appendonly yes
复制模板配置文件到各个实例,并修改端口
for i in `seq 2 6`;do cp 9001/redis.conf /usr/local/redis-cluster/900$i;done for i in `seq 2 6`;do sed -i "s/9001/900$i/g" /usr/local/redis-cluster/900$i/redis.conf;done
3)复制启动文件和集群工具
cp /usr/src/redis-4.0.12/src/redis-trib.rb /usr/local/redis-cluster/
cp /usr/local/redis/bin/redis-server /usr/local/redis-cluster/
4)启动各redis实例
for i in `seq 1 6`;do ./redis-server /usr/local/redis-cluster/900$i/redis.conf;done
5)搭建ruby环境
redis集群管理工具 redis-trib.rb 是依赖 ruby 环境。
yum install -y ruby
yum install -y rubygems
gem install redis
ps:报错
解决方法:
#安装RVM gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BD curl -sSL https://get.rvm.io | bash -s stable find / -name rvm -print source /usr/local/rvm/scripts/rvm #查看rvm库中已知的ruby版本 rvm list known #安装一个ruby版本 rvm install 2.4.1 #使用一个ruby版本 rvm use 2.4.1 #设置默认版本:(设置ruby2.4.1为默认的ruby,因为还安装有1.8.3) rvm use 2.4.1 --default #查看ruby版本 ruby --version #卸载一个已知版本 rvm remove 2.3.4 #安装redis gem install redis
6)搭建集群环境
第一步:搭建集群 ./redis-trib.rb create ,选择yes接受建议的配置
第二步:进入集群客户端 ./redis-cli -h 任意主机host -p 任意主机port -c,-c表示以集群方式连接redis
第三步:保存数据
第四步:cluster info 查询集群状态信息
第五步:cluster nodes 查询集群结点信息,这里有一个坑,后面会介绍
集群创建命令: ./redis-trib.rb create 创建集群,--replicas 1 给每个主机分配一个从机,后面其他参数都是redis服务的ip:port。最后输入yes来接受建议的配置
./redis-trib.rb create --replicas 1 172.17.245.146:9001 172.17.245.146:9002 172.17.245.146:9003 172.17.245.146:9004 172.17.245.146:9005 172.17.245.146:9006
/usr/local/redis/bin/redis-cli -h 172.17.245.146 -p 9001 -c
set testKey value cluster info
cluster nodes
可能存在的问题
Sorry, the cluster configuration file nodes.conf is already used by a different Redis Cluster node. Please make sure that different nodes use different cluster configuration files.
说的很明确,修改cluster-config-file nodes.conf 文件避免重名,或者删除该文件重新创建集群。
cluster nodes 查询集群节点信息
这是很重要的命令,我们需要关心的信息有:
第一个参数:节点ID
第二个参数:IP:PORT@TCP 这里一个坑,jedis-2.9.0之前的版本解析@出错
第三个参数:标志(Master,Slave,Myself,Fail...)
第四个参数:如果是从机则是主机的节点ID
最后两个参数:连接的状态和槽的位置。
三、 LAMP+Redis
1、LAMP+Redis工作机制
LAMP+Redis工作机制:用户通过浏览器访问LAMP网站,并以用户名和密码登录到网站,默认Redis缓存中没有该用户名和密码对应列表,PHP程序会读取MYSQL数据库中的用户名和密码,然后将用户名和密码缓存至Redis中,下次用户通过浏览器再次使用同样的用户名和密码登录网站,PHP无需从数据库中读取该用户和密码信息,而是直接优先从Redis缓存中读取并返回,从而减轻MYSQL数据库的压力。
Redis除了可以缓存用户名、密码,还可以换成PHP论坛各种数据,例如用户帖子、用户动态等等,如图所示:
要实现将LAMP PHP网站相关数据存入Redis,需要一台Redis服务器、PHP-redis连接驱动、PHP代码连接修改等。
2、 LAMP+Redis操作案例
LAMP PHP连接Redis,首先需安装Redis服务器,安装连接驱动,然后修改PHP网站配置文件,具体操作步骤如下:
1)在LAP上安装PHP-Redis连接驱动
cd /usr/src wget https://github.com/phpredis/phpredis/archive/4.0.1.tar.gz tar -zxf 4.0.1.tar.gz cd phpredis-4.0.1/ /usr/local/php/bin/phpize ./configure --with-php-config=/usr/local/php/bin/php-config make && make install
2)配置php
cp /usr/src/php-5.3.28/php.ini-production /usr/local/php/etc/php.ini (配置文件具体存放路径根据index.php测试页面) vim /usr/local/php5/etc/php.ini 添加如下两行代码 extension_dir = "/usr/local/php/lib/php/extensions/no-debug-zts-20131226" (红色的地方根据实际情况) extension=redis.so
重启Apache服务,写入phpinfo测试页面,通过浏览器访问,如图12-9所示,检查到存在Redis模块即可:
3) LAMP+Redis缓存测试
登录10.6.191.208 WEB服务器,修改Discuz PHP网站发布/usr/local/apache2/htdcos目录全局配置文件config_global.php,查找CONFIG MEMORY段,将redis server后改为Redis主服务器的IP 192.168.149.129即可,如图所示:
通过浏览器访问Apache PHP论坛网站,同时登陆Redis服务器,执行命令redis-cli进入Redis命令行,运行命令KEYS *,如图所示,存在以IOKLAN开头的key,则证明Redis成功缓存LAMP+Discuz网站信息数据。