Redis Sentinel 搭建(可以自己试试)
1.环境说明
主机名称 | IP地址 | redis版本和角色说明 |
redis-master | 192.168.56.11:6379 | redis 5.0.3(主) |
redis-slave01 | 192.168.56.12:6379 | redis 5.0.3(从) |
redis-slave02 | 192.168.56.13:6379 | redis 5.0.3(从) |
redis-master | 192.168.56.11:26379 | Sentinel01(主) |
redis-slave01 | 192.168.56.12:26379 | Sentinel02(从) |
redis-slave02 | 192.168.56.13:26379 | Sentinel03(从) |
2.部署Sentinel
# 端口 port 26379 # 是否后台启动 daemonize yes # pid文件路径 pidfile /var/run/redis-sentinel.pid # 日志文件路径 logfile "/var/log/sentinel.log" # 定义工作目录 dir /tmp # 定义Redis主的别名, IP, 端口,这里的2指的是需要至少2个Sentinel认为主Redis挂了才最终会采取下一步行为 sentinel monitor mymaster 127.0.0.1 6379 2 # 如果mymaster 30秒内没有响应,则认为其主观失效 sentinel down-after-milliseconds mymaster 30000 # 如果master重新选出来后,其它slave节点能同时并行从新master同步数据的台数有多少个,显然该值越大,所有slave节点完成同步切换的整体速度越快,但如果此时正好有人在访问这些slave,可能造成读取失败,影响面会更广。最保守的设置为1,同一时间,只能有一台干这件事,这样其它slave还能继续服务,但是所有slave全部完成缓存更新同步的进程将变慢。 sentinel parallel-syncs mymaster 1 # 该参数指定一个时间段,在该时间段内没有实现故障转移成功,则会再一次发起故障转移的操作,单位毫秒 sentinel failover-timeout mymaster 180000 # 不允许使用SENTINEL SET设置notification-script和client-reconfig-script。 sentinel deny-scripts-reconfig yes 复制代码
修改三台Sentinel的配置文件,如下
[root@redis-master ~]# grep -Ev "^$|#" /usr/local/redis/sentinel.conf port 26379 daemonize yes pidfile "/var/run/redis-sentinel.pid" logfile "/var/log/sentinel.log" dir "/tmp" sentinel monitor mymaster 192.168.56.11 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel deny-scripts-reconfig yes [root@redis-slave01 ~]# grep -Ev "^$|#" /usr/local/redis/sentinel.conf port 26379 daemonize yes pidfile "/var/run/redis-sentinel.pid" logfile "/var/log/sentinel.log" dir "/tmp" sentinel monitor mymaster 192.168.56.11 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel deny-scripts-reconfig yes [root@redis-slave02 ~]# grep -Ev "^$|#" /usr/local/redis/sentinel.conf port 26379 daemonize yes pidfile "/var/run/redis-sentinel.pid" logfile "/var/log/sentinel.log" dir "/tmp" sentinel monitor mymaster 192.168.56.11 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel deny-scripts-reconfig yes 复制代码
3.启动Sentinel 启动的顺序:主Redis --> 从Redis --> Sentinel1/2/3
[root@redis-master ~]# redis-sentinel /usr/local/redis/sentinel.conf [root@redis-master ~]# ps -ef |grep redis root 1295 1 0 14:03 ? 00:00:06 /usr/local/redis/src/redis-server 192.168.56.11:6379 root 1407 1 1 14:40 ? 00:00:00 redis-sentinel *:26379 [sentinel] root 1412 1200 0 14:40 pts/1 00:00:00 grep --color=auto redis [root@redis-slave01 ~]# redis-sentinel /usr/local/redis/sentinel.conf [root@redis-slave01 ~]# ps -ef |grep redis root 1625 1 0 14:04 ? 00:00:06 /usr/local/redis/src/redis-server 192.168.56.12:6379 root 1715 1 1 14:41 ? 00:00:00 redis-sentinel *:26379 [sentinel] root 1720 1574 0 14:41 pts/0 00:00:00 grep --color=auto redis [root@redis-slave02 ~]# redis-sentinel /usr/local/redis/sentinel.conf [root@redis-slave02 ~]# ps -ef |grep redis root 1628 1 0 14:07 ? 00:00:06 /usr/local/redis/src/redis-server 192.168.56.13:6379 root 1709 1 0 14:42 ? 00:00:00 redis-sentinel *:26379 [sentinel] root 1714 1575 0 14:42 pts/0 00:00:00 grep --color=auto redis 复制代码
4.Sentinel操作
[root@redis-master ~]# redis-cli -p 26379 #哨兵模式查看 127.0.0.1:26379> sentinel master mymaster #输出被监控的主节点的状态信息 1) "name" 2) "mymaster" 3) "ip" 4) "192.168.56.11" 5) "port" 6) "6379" 7) "runid" 8) "bae06cc3bc6dcbff7c2de1510df7faf1a6eb6941" 9) "flags" 10) "master" ...... 127.0.0.1:26379> sentinel slaves mymaster #查看mymaster的从信息,可以看到有2个从节点 1) 1) "name" 2) "192.168.56.12:6379" 3) "ip" 4) "192.168.56.12" 5) "port" 6) "6379" 7) "runid" 8) "c86027e7bdd217cb584b1bd7a6fea4ba79cf6364" 9) "flags" 10) "slave" ...... 2) 1) "name" 2) "192.168.56.13:6379" 3) "ip" 4) "192.168.56.13" 5) "port" 6) "6379" 7) "runid" 8) "61597fdb615ecf8bd7fc18e143112401ed6156ec" 9) "flags" 10) "slave" ...... 127.0.0.1:26379> sentinel sentinels mymaster #查看其它sentinel信息 1) 1) "name" 2) "ba12e2a4023d2e9bcad282395ba6b14030920070" 3) "ip" 4) "192.168.56.12" 5) "port" 6) "26379" 7) "runid" 8) "ba12e2a4023d2e9bcad282395ba6b14030920070" 9) "flags" 10) "sentinel" ...... 2) 1) "name" 2) "14fca3f851e9e1bd3a4a0dc8a9e34bb237648455" 3) "ip" 4) "192.168.56.13" 5) "port" 6) "26379" 7) "runid" 8) "14fca3f851e9e1bd3a4a0dc8a9e34bb237648455" 9) "flags" 10) "sentinel" 复制代码
Redis Lua 脚本
再这里我想说下,为啥我们要用Lua脚本呢? Lua脚本的好处
redis对lua脚本的调用是原子性的,所以一些特殊场景,比如像实现分布式锁,我们可以放在lua中实现
下面我带大家搭建一个最简单lua脚本demo
- 添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 复制代码
- 编写Lua脚本 命名为 Test.lua 放在 resources下
local key = KEYS[1] --- 获取value local val = KEYS[2] --- 获取一个参数 local expire = ARGV[1] --- 如果redis找不到这个key就去插入 if redis.call("get", key) == false then --- 如果插入成功,就去设置过期值 if redis.call("set", key, val) then --- 由于lua脚本接收到参数都会转为String,所以要转成数字类型才能比较 if tonumber(expire) > 0 then --- 设置过期时间 redis.call("expire", key, expire) end return true end return false else return false end 复制代码
- 编写配置类
@Configuration public class LuaConfiguration { @Bean public DefaultRedisScript<Boolean> redisScript() { DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("Test.lua"))); redisScript.setResultType(Boolean.class); return redisScript; } } 复制代码
- 测试
@Test public void TestLua(){ System.out.println("测试Lua开始"); List<String> keys = Arrays.asList("testLua", "hello六脉神剑"); Boolean execute = stringRedisTemplate.execute(redisScript, keys, "10000"); System.out.println("测试Lua结束,并在下面打印结果"); String testLua = stringRedisTemplate.opsForValue().get("testLua"); System.out.println("结果是:"+testLua); } 复制代码
- 结果
测试Lua开始 2019-12-03 10:48:01.469 INFO 246868 --- [ main] io.lettuce.core.EpollProvider : Starting without optional epoll library 2019-12-03 10:48:01.471 INFO 246868 --- [ main] io.lettuce.core.KqueueProvider : Starting without optional kqueue library 测试Lua结束,并在下面打印结果 结果是:hello六脉神剑 复制代码
Redis使用Lua的好处
1.减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在redis服务器上完成。使用脚本,减少了网络往返时延。
2.原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。
3.复用:客户端发送的脚本会永久存储在Redis中,意味着其他客户端可以复用这一脚本而不需要使用代码完成同样的逻辑。
Redis使用Lua要注意的点
1.Lua脚本的bug特别可怕,由于Redis的单线程特点,一旦Lua脚本出现不会返回(不是返回值)得问题,那么这个脚本就会阻塞整个redis实例。
2.Lua脚本应该尽量短小实现关键步骤即可。(原因同上)
3.Lua脚本中不应该出现常量Key,这样会导致每次执行时都会在脚本字典中新建一个条目,应该使用全局变量数组KEYS和ARGV, KEYS和ARGV的索引都从1开始
4.传递给lua脚本的的键和参数:传递给lua脚本的键列表应该包括可能会读取或者写入的所有键。传入全部的键使得在使用各种分片或者集群技术时,其他软件可以在应用层检查所有的数据是不是都在同一个分片里面。另外集群版redis也会对将要访问的key进行检查,如果不在同一个服务器里面,那么redis将会返回一个错误。(决定使用集群版之前应该考虑业务拆分),参数列表无所谓。。
5.lua脚本跟单个redis命令和事务段一样都是原子的已经进行了数据写入的lua脚本将无法中断,只能使用SHUTDOWN NOSAVE杀死Redis服务器,所以lua脚本一定要测试好。
结尾
我擦就随便写了个主从和Lua,就这么多,哎,一把辛酸一把泪。下一章是最后一章了,看看怎么写吧。
因为博主也是一个开发萌新 我也是一边学一边写 我有个目标就是一周 二到三篇 希望能坚持个一年吧 希望各位大佬多提意见,让我多学习,一起进步