一:Redis基本知识
1、redis数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
1)String
string 类型是二进制安全的,包含任何数据。比如jpg图片或者序列化的对象。
string 类型是 Redis 最基本的数据类型,值最大能存储 512MB。
2)hash
hash 是一个键值(key=>value)对的集合。
hash 特别适合用于存储对象。
3)list
Redis 列表是简单的字符串列表。
4)set
string类型的无序集合。
5)zset
string类型元素的集合,不允许重复的成员且有序。
二:Redis安装、配置以及客户端运行
1、安装
略。
2、配置
配置文件位于 Redis 安装目录下,文件名为 redis.conf。
配置项有:
序号 | 配置项 | 说明 |
---|---|---|
1 |
daemonize no
|
Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no ) |
2 |
pidfile /var/run/redis.pid
|
当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定 |
3 |
port 6379
|
指定 Redis 监听端口,默认端口为 6379,作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口,因为 6379 在手机按键上 MERZ 对应的号码,而 MERZ 取自意大利歌女 Alessia Merz 的名字 |
4 |
bind 127.0.0.1
|
绑定的主机地址 |
5 |
timeout 300
|
当客户端闲置多长时间后关闭连接,如果指定为 0,表示关闭该功能 |
6 |
loglevel notice
|
指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 notice |
7 |
logfile stdout
|
日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null |
8 |
databases 16
|
设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id |
9 |
save <seconds> <changes>
Redis 默认配置文件中提供了三个条件: save 900 1 save 300 10 save 60 10000 分别表示 900 秒(15 分钟)内有 1 个更改,300 秒(5 分钟)内有 10 个更改以及 60 秒内有 10000 个更改。 |
指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 |
10 |
rdbcompression yes
|
指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大 |
11 |
dbfilename dump.rdb
|
指定本地数据库文件名,默认值为 dump.rdb |
12 |
dir ./
|
指定本地数据库存放目录 |
13 |
slaveof <masterip> <masterport>
|
设置当本机为 slav 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 |
14 |
masterauth <master-password>
|
当 master 服务设置了密码保护时,slav 服务连接 master 的密码 |
15 |
requirepass foobared
|
设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭 |
16 |
maxclients 128
|
设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息 |
17 |
maxmemory <bytes>
|
指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap 区 |
18 |
appendonly no
|
指定是否在每次更新操作后进行日志记录,Redis 在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 no |
19 |
appendfilename appendonly.aof
|
指定更新日志文件名,默认为 appendonly.aof |
20 |
appendfsync everysec
|
指定更新日志条件,共有 3 个可选值:
|
21 |
vm-enabled no
|
指定是否启用虚拟内存机制,默认值为 no,简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析 Redis 的 VM 机制) |
22 |
vm-swap-file /tmp/redis.swap
|
虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享 |
23 |
vm-max-memory 0
|
将所有大于 vm-max-memory 的数据存入虚拟内存,无论 vm-max-memory 设置多小,所有索引数据都是内存存储的(Redis 的索引数据 就是 keys),也就是说,当 vm-max-memory 设置为 0 的时候,其实是所有 value 都存在于磁盘。默认值为 0 |
24 |
vm-page-size 32
|
Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,vm-page-size 是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;如果存储很大大对象,则可以使用更大的 page,如果不确定,就使用默认值 |
25 |
vm-pages 134217728
|
设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。 |
26 |
vm-max-threads 4
|
设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4 |
27 |
glueoutputbuf yes
|
设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 |
28 |
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
|
指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 |
29 |
activerehashing yes
|
指定是否激活重置哈希,默认为开启(后面在介绍 Redis 的哈希算法时具体介绍) |
30 |
include /path/to/local.conf
|
指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 |
3、客户端运行
redis-cli
测试本地redis是否启动:
PING
输出:PONG ,即说明启动了。
连接到远程服务器上的redis:
$ redis-cli -h host -p port -a password
三:Redis读写操作指令
通过第二步,连接到redis客户端后, 即可通过指令进行一系列操作。
在redis中,针对不同的数据类型,有不同的读写指令。
1、针对key的操作
redis 127.0.0.1:6379> COMMAND KEY_NAME
针对key的操作指令有:
序号 | 命令及描述 |
---|---|
1 | DEL key 该命令用于在 key 存在时删除 key。 |
2 | DUMP key 序列化给定 key ,并返回被序列化的值。 |
3 | EXISTS key 检查给定 key 是否存在。 |
4 | EXPIRE key seconds 为给定 key 设置过期时间,以秒计。 |
5 | EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 |
6 | PEXPIRE key milliseconds 设置 key 的过期时间以毫秒计。 |
7 | PEXPIREAT key milliseconds-timestamp 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计 |
8 | KEYS pattern 查找所有符合给定模式( pattern)的 key 。 |
9 | MOVE key db 将当前数据库的 key 移动到给定的数据库 db 当中。 |
10 | PERSIST key 移除 key 的过期时间,key 将持久保持。 |
11 | PTTL key 以毫秒为单位返回 key 的剩余的过期时间。 |
12 | TTL key 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 |
13 | RANDOMKEY 从当前数据库中随机返回一个 key 。 |
14 | RENAME key newkey 修改 key 的名称 |
15 | RENAMENX key newkey 仅当 newkey 不存在时,将 key 改名为 newkey 。 |
16 | TYPE key 返回 key 所储存的值的类型。 |
2、针对String类型数据的操作
序号 | 命令及描述 |
---|---|
1 | SET key value 设置指定 key 的值 |
2 | GET key 获取指定 key 的值。 |
3 | GETRANGE key start end 返回 key 中字符串值的子字符 |
4 | GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 |
5 | GETBIT key offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。 |
6 | MGET key1 [key2..] 获取所有(一个或多个)给定 key 的值。 |
7 | SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 |
8 | SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。 |
9 | SETNX key value 只有在 key 不存在时设置 key 的值。 |
10 | SETRANGE key offset value 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。 |
11 | STRLEN key 返回 key 所储存的字符串值的长度。 |
12 | MSET key value [key value ...] 同时设置一个或多个 key-value 对。 |
13 | MSETNX key value [key value ...] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。 |
14 | PSETEX key milliseconds value 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。 |
15 | INCR key 将 key 中储存的数字值增一。 |
16 | INCRBY key increment 将 key 所储存的值加上给定的增量值(increment) 。 |
17 | INCRBYFLOAT key increment 将 key 所储存的值加上给定的浮点增量值(increment) 。 |
18 | DECR key 将 key 中储存的数字值减一。 |
19 | DECRBY key decrement key 所储存的值减去给定的减量值(decrement) 。 |
20 | APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。 |
3、针对Hash类型数据的操作
序号 | 命令及描述 |
---|---|
1 | HDEL key field1 [field2] 删除一个或多个哈希表字段 |
2 | HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。 |
3 | HGET key field 获取存储在哈希表中指定字段的值。 |
4 | HGETALL key 获取在哈希表中指定 key 的所有字段和值 |
5 | HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。 |
6 | HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。 |
7 | HKEYS key 获取所有哈希表中的字段 |
8 | HLEN key 获取哈希表中字段的数量 |
9 | HMGET key field1 [field2] 获取所有给定字段的值 |
10 | HMSET key field1 value1 [field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。 |
11 | HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。 |
12 | HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。 |
13 | HVALS key 获取哈希表中所有值 |
14 | HSCAN key cursor [MATCH pattern] [COUNT count] 迭代哈希表中的键值对。 |
4、针对List类型数据的操作
序号 | 命令及描述 |
---|---|
1 | BLPOP key1 [key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
2 | BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
3 | BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
4 | LINDEX key index 通过索引获取列表中的元素 |
5 | LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者后插入元素 |
6 | LLEN key 获取列表长度 |
7 | LPOP key 移出并获取列表的第一个元素 |
8 | LPUSH key value1 [value2] 将一个或多个值插入到列表头部 |
9 | LPUSHX key value 将一个值插入到已存在的列表头部 |
10 | LRANGE key start stop 获取列表指定范围内的元素 |
11 | LREM key count value 移除列表元素 |
12 | LSET key index value 通过索引设置列表元素的值 |
13 | LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
14 | RPOP key 移除列表的最后一个元素,返回值为移除的元素。 |
15 | RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 |
16 | RPUSH key value1 [value2] 在列表中添加一个或多个值 |
17 | RPUSHX key value 为已存在的列表添加值 |
5、针对Set类型数据的操作
序号 | 命令及描述 |
---|---|
1 | SADD key member1 [member2] 向集合添加一个或多个成员 |
2 | SCARD key 获取集合的成员数 |
3 | SDIFF key1 [key2] 返回给定所有集合的差集 |
4 | SDIFFSTORE destination key1 [key2] 返回给定所有集合的差集并存储在 destination 中 |
5 | SINTER key1 [key2] 返回给定所有集合的交集 |
6 | SINTERSTORE destination key1 [key2] 返回给定所有集合的交集并存储在 destination 中 |
7 | SISMEMBER key member 判断 member 元素是否是集合 key 的成员 |
8 | SMEMBERS key 返回集合中的所有成员 |
9 | SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合 |
10 | SPOP key 移除并返回集合中的一个随机元素 |
11 | SRANDMEMBER key [count] 返回集合中一个或多个随机数 |
12 | SREM key member1 [member2] 移除集合中一个或多个成员 |
13 | SUNION key1 [key2] 返回所有给定集合的并集 |
14 | SUNIONSTORE destination key1 [key2] 所有给定集合的并集存储在 destination 集合中 |
15 | SSCAN key cursor [MATCH pattern] [COUNT count] 迭代集合中的元素 |
6、针对ZSet类型数据的操作
四:Redis高级特性
1、redis事务
Redis 事务可以一次执行多个命令:以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务。
需要注意的是:
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
2、redis服务器管理指令
序号 | 命令及描述 |
---|---|
1 | BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作 |
2 | BGSAVE 在后台异步保存当前数据库的数据到磁盘 |
3 | CLIENT KILL [ip:port] [ID client-id] 关闭客户端连接 |
4 | CLIENT LIST 获取连接到服务器的客户端连接列表 |
5 | CLIENT GETNAME 获取连接的名称 |
6 | CLIENT PAUSE timeout 在指定时间内终止运行来自客户端的命令 |
7 | CLIENT SETNAME connection-name 设置当前连接的名称 |
8 | CLUSTER SLOTS 获取集群节点的映射数组 |
9 | COMMAND 获取 Redis 命令详情数组 |
10 | COMMAND COUNT 获取 Redis 命令总数 |
11 | COMMAND GETKEYS 获取给定命令的所有键 |
12 | TIME 返回当前服务器时间 |
13 | COMMAND INFO command-name [command-name ...] 获取指定 Redis 命令描述的数组 |
14 | CONFIG GET parameter 获取指定配置参数的值 |
15 | CONFIG REWRITE 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 |
16 | CONFIG SET parameter value 修改 redis 配置参数,无需重启 |
17 | CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据 |
18 | DBSIZE 返回当前数据库的 key 的数量 |
19 | DEBUG OBJECT key 获取 key 的调试信息 |
20 | DEBUG SEGFAULT 让 Redis 服务崩溃 |
21 | FLUSHALL 删除所有数据库的所有key |
22 | FLUSHDB 删除当前数据库的所有key |
23 | INFO [section] 获取 Redis 服务器的各种信息和统计数值 |
24 | LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示 |
25 | MONITOR 实时打印出 Redis 服务器接收到的命令,调试用 |
26 | ROLE 返回主从实例所属的角色 |
27 | SAVE 同步保存数据到硬盘 |
28 | SHUTDOWN [NOSAVE] [SAVE] 异步保存数据到硬盘,并关闭服务器 |
29 | SLAVEOF host port 将当前服务器转变为指定服务器的从属服务器(slave server) |
30 | SLOWLOG subcommand [argument] 管理 redis 的慢日志 |
31 | SYNC 用于复制功能(replication)的内部命令 |
五:Redis深入
1、redis数据备份与恢复
1)备份
redis 127.0.0.1:6379> SAVE
将在 redis 安装目录中创建dump.rdb文件。
2)恢复
将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。
2、redis安全——密码
一般redis默认是不设置密码的,无需通过验证即可连接redis服务。
但是如果有需要,也可以通过配置文件,设置需要密码登录。
3、redis性能测试
在redis目录下,有一个性能测试工具:redis-benchmark。
运行:
redis-benchmark [option] [option value]
可以进行redis性能测试,可选项有:
序号 | 选项 | 描述 | 默认值 |
---|---|---|---|
1 | -h | 指定服务器主机名 | 127.0.0.1 |
2 | -p | 指定服务器端口 | 6379 |
3 | -s | 指定服务器 socket | |
4 | -c | 指定并发连接数 | 50 |
5 | -n | 指定请求数 | 10000 |
6 | -d | 以字节的形式指定 SET/GET 值的数据大小 | 2 |
7 | -k | 1=keep alive 0=reconnect | 1 |
8 | -r | SET/GET/INCR 使用随机 key, SADD 使用随机值 | |
9 | -P | 通过管道传输 <numreq> 请求 | 1 |
10 | -q | 强制退出 redis。仅显示 query/sec 值 | |
11 | --csv | 以 CSV 格式输出 | |
12 | -l | 生成循环,永久执行测试 | |
13 | -t | 仅运行以逗号分隔的测试命令列表。 | |
14 | -I | Idle 模式。仅打开 N 个 idle 连接并等待。 |
六:Redis简单使用
1、Java使用redis
1)下载驱动包:jedis
2)通过ip连接redis
import redis.clients.jedis.Jedis; public class RedisJava { public static void main(String[] args) { //连接本地的 Redis 服务 Jedis jedis = new Jedis("ip"); //查看服务是否运行 System.out.println("服务正在运行: "+jedis.ping()); } }
3)字符串操作实例
//设置 redis 字符串数据 jedis.set("stringKey", "value"); // 获取存储的数据并输出 System.out.println("redis 存储的字符串为: "+ jedis.get("stringKey"));
4)列表操作实例
//存储数据到列表中 jedis.lpush("listKey", "1"); jedis.lpush("lietKey", "2"); jedis.lpush("listKey", "3"); // 获取存储的数据并输出 List<String> list = jedis.lrange("listKey", 0 ,2); for(int i=0; i<list.size(); i++) { System.out.println("列表项为: "+list.get(i)); }
2、Python使用redis
1)安装库:redis、redispy、redisdump
2)连接redis
from redis import StrictRedis redis = StrictRedis(host='localhost', port=6379, db=0, password=‘pwd')
3)操作数据
使用redis.api(kwargs),具体api指令参考上文。
4)redis备份与恢复
RedisDump库提供了强大的Redis数据的导入和导出功能:redis-dump
用于导出数据,redis-load
用于导入数据。
备份:
redis-dump -选项 参数值
其中-u
代表Redis连接字符串,-d
代表数据库,-s
代表导出之后的休眠时间,-c
代表分块大小,默认是10000,-f
代表导出时的过滤器,-O
代表禁用运行时优化,-V
用于显示版本,-D
表示开启调试。
恢复:
redis-load -选项 参数值
其中-u
代表Redis连接字符串,-d
代表数据库代号,默认是全部,-s
代表导出之后的休眠时间,-n
代表不检测UTF-8编码,-V
表示显示版本,-D
表示开启调试。
七:Redis单例模式、主从模式、哨兵模式、集群模式的配置——通过配置来实现各种模式的部署
1、单例模式
单例模式就是最简单的下载安装并启动。
1)在用作缓存的服务器上,下载并安装好redis。
2)启动redis:进入redis安装目录下,执行:
./redis-server [配置文件]
3)在web程序中,通过代码连接redis,进行数据存取操作。
4) 客户端操作:通过redis-cli连接到redis服务器,可以进行备份与恢复等一系列运维工作。
2、主从模式
由于单例模式只有一个redis服务器,一旦通信障碍或redis服务器挂掉了,那缓存就不可用了。
为了解决这个问题,redis提供了主从模式部署:在多台服务器上部署多个redis实例,一主多从。
其中,主redis实例负责读和写操作,从redis只能读。
主redis的写操作会触发数据备份到各个从redis,从而可以避免某台服务器挂掉之后,缓存无法读取的情况。
- 主从模式的一个作用是备份数据,这样当一个节点损坏(指不可恢复的硬件损坏)时,数据因为有备份,可以方便恢复。
- 另一个作用是负载均衡,所有客户端都访问一个节点肯定会影响Redis工作效率,有了主从以后,查询操作就可以通过查询从节点来完成。
- 一个Master可以有多个Slaves
- 默认配置下,master节点可以进行读和写,slave节点只能进行读操作,写操作被禁止
- 不要修改配置让slave节点支持写操作,没有意义,原因一,写入的数据不会被同步到其他节点;原因二,当master节点修改同一条数据后,slave节点的数据会被覆盖掉
- slave节点挂了不影响其他slave节点的读和master节点的读和写,重新启动后会将数据从master节点同步过来
- master节点挂了以后,不影响slave节点的读,Redis将不再提供写服务,master节点启动后Redis将重新对外提供写服务。
- master节点挂了以后,不会slave节点重新选一个master
当master节点设置密码时:
- 客户端访问master需要密码
- 启动slave需要密码,在配置中进行配置即可
- 客户端访问slave不需要密码
1)主redis的部署
参考单例模式的redis部署并启动即可,记录其 ip和端口 备用。
2)从redis的部署
在其他服务器安装redis后,修改其配置文件,添加以下配置项:
slaveof 主机IP 主机端口
3)代码中使用redis
参考单例模式的使用即可。
主从模式直接通过部署和配置就可以实现了,无需编程实现。
3、哨兵模式
第二点中提到的主从模式解决了某台服务器挂掉之后,缓存无法读取的问题。但是由于只有主redis才能进行写操作,这又会引发新的问题——主redis挂掉后,无法再进行写缓存操作了。
因此,我们就需要面临这种情况:当主redis挂掉之后,能自动从剩下的redis服务器当中选出一个接班人,使之成为“主redis”。
redis 2.8之后提供了哨兵模式,满足了以上需求:部署形式还是同主从模式一样,一台主redis,多台从redis。
区别在于启动时,不是使用redis-server启动,而是使用以下方式启动:
1)进入redis安装目录,类似于配置redis的配置文件redis.conf一样,还有一个哨兵配置文件sentinel.conf,我们对它进行配置:具体配置项和含义,参考:http://doc.redisfans.com/topic/sentinel.html
2)配置完成后,以哨兵模式运行redis:
redis-sentinel /path_to/sentinel.conf
3)代码中使用哨兵池来获取redis对象:
Set<String> sentinels = new HashSet<>( Arrays.asList("ip:port", "ip:port", "ip:port")); GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); //此处对poolConfig进行设置 JedisSentinelPool pool = new JedisSentinelPool("redis_pool", sentinels, poolConfig); Jedis jedis = pool.getResource(); //使用jedis进行操作 //使用完直接close即可,会自动判断,若单个连接则关闭,在连接池内则归还 jedis.close();
哨兵模式的原理:
对于一组主从节点,sentinel对其进行了加装,运行了一个守护进程与其他哨兵进行通信,组成了一个监控网络。
sentinel节点之间会相互发送消息,以检测各个sentinel节点是否正常工作,并且sentinel节点也会向主从节点发送消息,以检测监控的主从节点是否正常工作。
如果主节点因为故障下线,那么某个sentinel节点发送检测消息给主节点时,如果在指定时间内收不到回复,那么该sentinel就会主观判断该主节点已经下线,同时其会发送消息给其余的sentinel节点询问其是否“认为”该主节点已下线[投票机制],其余的sentinel收到消息后也会发送检测消息给主节点,如果其认为该主节点已经下线,那么其会回复向其询问的sentinel节点,告知其也认为主节点已经下线。
当该sentinel节点最先收到超过指定数目的回复数,那么其就会对主节点进行故障转移工作:
在从节点中选取某个从节点向其发送slaveof no one(假设选取的从节点为127.0.0.1:6380),使其称为独立的节点(也就是新的主节点);
然后sentinel向其余的从节点发送slaveof 127.0.0.1 6380命令使它们重新成为新的主节点的从节点;
重新分配之后,sentinel节点集合仍会继续监控已经下线的主节点(假设为127.0.0.1:6379),如果其重新上线,那么sentinel会向其发送slaveof命令,使其成为新的主机点的从节点,如此故障转移工作完成。
- sentinel模式是建立在主从模式的基础上,如果只有一个Redis节点,sentinel就没有任何意义
- 当master节点挂了以后,sentinel会在slave中选择一个做为master,并修改它们的配置文件,其他slave的配置文件也会被修改,比如slaveof属性会指向新的master
- 当master节点重新启动后,它将不再是master而是做为slave接收新的master节点的同步数据
- sentinel因为也是一个进程有挂掉的可能,所以sentinel也会启动多个形成一个sentinel集群
- 当主从模式配置密码时,sentinel也会同步将配置信息修改到配置文件中,不许要担心。
- 一个sentinel或sentinel集群可以管理多个主从Redis。
- sentinel最好不要和Redis部署在同一台机器,不然Redis的服务器挂了以后,sentinel也挂了
4、集群模式
第三点的哨兵模式已经足以满足大部分的使用场景,保障了缓存的高可用性。
但是当遇到这样一种场景:某个系统的缓存数据非常庞大,单机内存或单机流量已经不足以承载时,哨兵模式也会被查宕机【因为每台redis实例缓存的内容都是一样的】。
这个时候,我们就要考虑一种分部署存储的方案——将大数据量的缓存内容打散,存储到多个以 哨兵模式 部署到redis体系中。
举个例子,我们有6台服务器,我们取A、B、C三台以哨兵模式部署,A主,BC从,称为“体系1”;D、E、F同样以哨兵模式部署,D主,EF从,称为“体系2”。那么 体系1 和 体系2 组成了一个集群。
其中,体系1中A、B、C三台机器存储的内容是相同的,体系2中D、E、F存储的内容是相同的,但是体系1和体系2中的内容是不同的。我们可以将缓存数据根据算法,平均分配到集群中每个体系中去存储,分布式存储保证了数据的均衡存放并且基于哨兵模式的体系又能保证高可用性。
这个平均分配存放和读写的算法称为“一致性Hash”算法,在很多地方都要使用该思想,此处不再详述。
需要注意的是,基于一致性hash算法实现的方案不是完美的,当节点数变化时,Hash环上中部分数据会重新排布,并且节点越少受影响的数据越多。
鉴于此,redis使用虚拟槽位来避免节点数变化导致数据重排问题:
redis集群定义了2^32(16384)个虚拟的slot,均匀分布在Hash环上;
读写数据时,根据key值的hashCode,在环上找到对应位置的slot,在该槽对应的redis集群节点进行数据读写;
在部署时,将0~16384尽量平均分配给各个节点,每个节点可以映射一段范围的槽位,在集群横向扩展时,只需修改配置文件中各个节点对应的slot范围即可。
也就是说,此处将集群节点与数据存储位置解耦,节点数只影响每个节点可操作的槽位范围,而数据的读写位置只与槽位相关。
集群模式的部署也是通过配置来实现的:
1)修改redis.conf文件,开启集群模式
cluster-enabled yes cluster-node-timeout 15000 cluster-config-file "nodes.conf"
2)将多台服务器按上述配置修改好后启动【此处不影响主从模式和哨兵模式的配置】,需要记录下各个redis实例的ip和端口。
3)创建集群:使用redis-trib程序来执行指令
进入redis安装目录下,执行指令,如:
./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
命令的意义如下:
- 给定 redis-trib.rb 程序的命令是 create , 这表示我们希望创建一个新的集群。
- 选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
- 之后跟着的其他参数则是实例的地址列表, 我们希望程序使用这些地址所指示的实例来创建新集群。
简单来说, 以上命令的意思就是让 redis-trib 程序创建一个包含三个主节点和三个从节点的集群。
然后一路输入yes、回车即可。
此时集群搭建完毕并开始运行。
4)集群重新分片
当我们对集群的机器有所增减,需要对集群重新分片时,可以通过redis-trib程序来执行重新分片指令,如:
$ ./redis-trib.rb reshard 127.0.0.1:7000
你只需要指定集群中其中一个节点的地址, redis-trib 就会自动找到集群中的其他节点并重新分片。
针对集群模式的具体操作和原理探究,可以参考:http://doc.redisfans.com/topic/cluster-tutorial.html
5)代码程序中使用集群
//使用需要的构造方法构造JedisCluster JedisCluster jedisCluster = new JedisCluster(); //JedisCluster 的使用,JedisCluster 具备Redis大多数方法 jedisCluster.set("key", "value"); //使用完后关闭 jedisCluster.close();
八:Redis持久化
1、RDB模式
在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
RDB 是一个非常紧凑的文件,它保存了 Redis 在某个时间点上的数据集,可以随时将数据集还原到不同的版本, 非常适用于灾难恢复。
缺点是:由于它每隔一个时间段才备份,若在两个时间节点之间服务器断电,会导致这期间数据丢失。
2、AOF模式
记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。
Redis 可以同时使用 AOF 持久化和 RDB 持久化,当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集。
缺点:AOF 文件的体积通常要大于 RDB 文件的体积。