From d73c25af48116da2a33190c85be66afadfe54de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=96=87=E6=B5=9A?= Date: Fri, 3 Apr 2020 17:10:44 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=BB=A3=E7=A0=81=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E5=92=8C=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/redis-good.md | 62 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/docs/redis-good.md b/docs/redis-good.md index 9cc1fd2..93b69c2 100644 --- a/docs/redis-good.md +++ b/docs/redis-good.md @@ -21,7 +21,7 @@ 1.一个进程中的多个线程,多个线程并发访问同一个资源的时候,如何解决线程安全问题。 2.一个分布式架构系统中的两个模块同时去访问一个文件对文件进行读写操作 3.多个应用对同一条数据做修改的时候,如何保证数据的安全性 - 在但一个进程中,我们可以用到synchronized、lock之类的同步操作去解决,但是对于分布式架构下多进程的情况下, + 但在一个进程中,我们可以用到synchronized、lock之类的同步操作去解决,但是对于分布式架构下多进程的情况下, 如何做到跨进程的锁。就需要借助一些第三方手段来完成 **设计一个分布式所需要解决的问题,分布式锁解决方案(数据库方案)** @@ -51,8 +51,8 @@ 1.锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁 2.锁是非阻塞的,数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列 要想再次获得锁就要再次触发获得锁操作 - 3.锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁 - + 3.锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁(要解决这个问题可以在表中多加一列用于记录线程名称,通过判断这个列来实现重入) + **ZK方案** ZK方案实现之前你要先了解ZK关于他的节点的几个特性: @@ -142,9 +142,32 @@ 1. Redis在执行EVAL命令时会计算脚本的SHA1摘要并记录在脚本缓存中 2. 执行EVALSHA命令时Redis会根据提供的摘要从脚本缓存中查找对应的脚本内容 如果找到了就执行脚本,否则返回“NOSCRIPT No matching script,Please use EVAL” - - **Redis(2.6以后)--lua脚本运行限制** - + +演示流程: + +```shell +# 计算出脚本的sha1,用于后续验证 +127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'" +"232fd51614574cf0867b83d384a5e898cfd24e5a" +# 判断脚本存在 +127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a +1) (integer) 1 +# 清空所有脚本 +127.0.0.1:6379> SCRIPT FLUSH +OK +# 判断脚本不存在 +127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a +1) (integer) 0 +# 直接运行脚本,redis会自动进行缓存 +127.0.0.1:6379> EVAL "return 'hello moto'" 0 +"hello moto" +# 根据缓存中的sha1来直接运行脚本 +127.0.0.1:6379> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0 +"hello moto" +``` + + **Redis(2.6以后)--lua脚本运行限制** + redis的脚本执行是原子的,即脚本执行期间Redis不会执行其他命令 所有的命令必须等待脚本执行完以后才能执行。为了防止某个脚本执行时间过程导致Redis无法提供服务 Redis提供了lua-time-limit参数限制脚本的最长运行时间--默认是5秒钟 @@ -173,3 +196,30 @@ lua脚本一致存在于redis 中可以 限制每秒钟的请求数实现限流! +这里提供一种基于zset的信号量实现方式: + +- zset的成员为uuid,唯一代表某一个线程,分数是当前的时间戳 +- 限制zset中给的成员数量来实现限流 +- 根据zset的分值(时间戳)按大小进行排序,移除某一范围的成员,实现超时移除处理 + +假定zset的名字为`xhlZset`,获取信号量: + +``` +// 被动触发超时处理:将已经超时的信号量移除出zset +zremrangebyscore xhlZset -inf now-timeout + +// 如果信号量的数量没有超出限制 +if zcard xhlZset < limit { + // 添加,记录uuid以及当前时间戳now + zadd xhlZset now uuid + return 1 +} +return 0 +``` + +释放信号量 + +``` +zrem xhlZset uuid +``` +