Redis lua脚本简要学习


背景

上周督促客户从Windows平台升级到了Linux平台.
redis一周相安无事.
但是这周一突然又出现了卡断和慢的情况.
只能继续进行分析.

分析思路

现场日志里面出现了大量的错误提示:
BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. 不管用chatGPT后者是其他工具都可以查询出来:
Redis执行lua脚本时间太长了. 导致其他客户端无法获取结果集. 然后计划通过redis的slowlog 查询验证一下自己的想法

分析过程


我在自己的测试机器上面执行了 slowlog get 获取如下:

10) 1) (integer) 996
2) (integer) 1685314080
3) (integer) 10513
4) 1) "EVALSHA"
2) "7ae4b3e7f4bf3b0c3470baf33dd1b4941599b520"
3) "879" 发现最近十条慢命令全是id为: 7ae4b3e7f4bf3b0c3470baf33dd1b4941599b520 的lua脚本导致的. 督促现场抓紧获取指令:
现场反馈的图片与我这边一致
但是不太一样的是:
现场有四万个键值对耗时 接近 9 秒钟.
比我这边有非常大的差距. 我这边又让研发同事去另外一个大项目查询了下: 2万个参数. 执行时间为:58毫秒左右 389654
1685325926
57581
EVALSHA
7ae4b3e7f4bf3b0c3470baf33dd1b4941599b520
20855 基本上明确是此lua脚本导致的卡顿

问题再现以及缓解

网上查了一点简单资料, 准备做一下实验
在一个redis的客户端上面你执行命令
eval "while 0==0 do end" 0
然后在另外的redis客户端验证
redis-cli
get 1
get 2
会提示: "BUSY Redis is busy running a script."
然后执行: script KILL
再执行
get 1 就可以正常给出结果了. 说明问题基本上可以再现. 缓解方式: 如果不是一个很需要数据一致性的场景, 可以进行一下SCRIPT KILL
后期解决方式, 应该可以分组,每组不超过1万或者是1000 进行处理, 循环进行清理操作.

未解决的问题

翻找了一早上资料, 没有解决如何根据evalsha 的sha1值反向获取具体的lua脚本.
chatgpt给的结果就是垃圾, 一个get 一个list命令 script 根本没有这些参数. 没办法只能求助于开发:
private final static DefaultRedisScript SessionExistRedisScript = new DefaultRedisScript<>(
"local expires = ''\n" +
"for i=1, #KEYS do\n" +
" if(redis.call('EXISTS','caf-session:sessions:'..KEYS[i]) == 0)\n" +
" then\n" +
" expires = expires..';'..KEYS[i]\n" +
" end\n" +
"end\n" +
"return expires", String.class
);

问题思考

前端时间刚整理了因为Redis的scan导致机器卡顿宕机的问题
今天早上在看ergonomics导致full GC无法提供服务的现象. 我突然感觉redis因为单线程的处理逻辑, 如果大家都需要同步的获取redis的结果
那么每次redis执行吗命令都相当于在做一次minor GC
如果是一个slowlog. 那么就相当于所有连接着一个redis的所有应用服务器一起在做STW.的full GC
所以从时间链上分析. 任何single point 都需要非常严格的重视. 所以研发写的那一套lua脚本非常值得研究与修改.

lua脚本的优点

(1) 减少网络开销: 在Redis操作需求需要向Redis发送5次请求,
而使用脚本功能完成同样的操作只需要发送一个请求即可,减少了网络往返时延。
(2) 原子操作: Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。
换句话说在编写脚本的过程中无需担心会出现竞态条件,也就无需使用事务。事务可以完成的所有功能都可以用脚本来实现。
(3) 复用: 客户端发送的脚本会永久存储在Redis中,
这就意味着其他客户端(可以是其他语言开发的项目)可以复用这一脚本而不需要使用代码完成同样的逻辑。
(4) 速度快:见 与其它语言的性能比较, 还有一个 JIT编译器可以显著地提高多数任务的性能;
对于那些仍然对性能不满意的人, 可以把关键部分使用C实现, 然后与其集成, 这样还可以享受其它方面的好处。

关于lua脚本的继续学习

前端时间想学习 openresty 使用lua脚本.
但是非常可耻的立了flag没有学习深入下去.
所以发现还是遇到问题督促学习更好.
需要拥抱问题, 不能害怕问题, 通过问题来学习和提高自己. lua脚本的基础知识
lua脚本是解释性的语言, 跟python和shell 都比较类似.
print("hello 济南小老虎!")
就是一个最简单的 hello world的脚本. 数据类型:
nil,布尔,浮点数,字符串,函数,线程,关联数组(table等) 循环判断
while( true )
do
print("测试循环")
os.execute("sleep " .. 2)
end

Redis里面eval等学习

eval 其实一个非常不安全的命令
很多一句话木马基本上都是基于这个吗精灵来做的
在js,php,等语言里面都有存在.
redis 里面 eval 是用于调用lua脚本的命令. eval以及script脚本可以实现很多lua脚本的调用和使用.
学习和举例如下:
script load "while (true) do end"
会返回一个hash值如下: 127.0.0.1:6379> script load "while (true) do end"
"f926d8b19784f2c8c63b04288b32cb8de66070ba" 我理解此处就像是数据库绑定变量后可以避免hard parse 的方式一样.
下次执行时可以使用 evalsha f926d8b19784f2c8c63b04288b32cb8de66070ba 0 注意需要加最后一个0 用于指代参数个数
此时就可以执行命令了
等效率执行
eval "while (true) do end" 0 # 注意执行此命令会阻塞产品的使用, 必须尽早执行kill处理.
# 因为redis默认的lua脚本超时时间是 5 seconds 所以只会kill 5s 以上的script.
# 举例如下
# 我执行删除操作. 其实一直没有返回, 因为还没到五秒
127.0.0.1:6379> script kill
OK
(2.23s)
# 执行 lua脚本的返回情况如下:
(error) ERR Error running script (call to f_f926d8b19784f2c8c63b04288b32cb8de66070ba): @user_script:1: Script killed by user with SCRIPT KILL...
(5.00s)

Redis lua脚本简要学习的更多相关文章

  1. Redis Lua脚本完全入门

    1. 前言 Redis是高性能的KV内存数据库,除了做缓存中间件的基本作用外还有很多用途,比如胖哥以前分享的Redis GEO地理位置信息计算.Redis提供了丰富的命令来供我们使用以实现一些计算.R ...

  2. Redis Lua脚本调试

    从版本3.2开始,Redis包含一个完整的Lua调试器,可以用来使编写复杂Redis脚本的任务更加简单. 由于Redis 3.2仍处于测试阶段,请unstable从Github 下载Redis 的分支 ...

  3. Redis Lua 脚本使用

    本文转载自Redis Lua 脚本使用 Lua 简介 Lua语言提供了如下几种数据类型:booleans(布尔).numbers(数值).strings(字符串).tables(表格). 下面是一些 ...

  4. redis lua脚本学习

    语法格式(常见) a = 5 -- 全局变量 local b = 5 -- 局部变量 Eval的使用 EVAL script numkeys key [key ...] arg [arg ...] 首 ...

  5. Redis Lua脚本原理

    2.6版本之后支持嵌入Lua脚本,客户端使用Lua脚本,直接在服务器端原子的执行多条命令 Lua脚本执行过程 创建并修改Lua环境 1 创建基础Lua环境 2 载入函数库 3 创建全局表格Lua 4 ...

  6. 在Spring中使用Redis Lua脚本批量删除缓存

    背景 之前分享了一篇利用lua脚本批量删除redis的key的文章.现在项目中我打算使用spring的缓存,而Spring缓存以前我是用ehcache来做实现的.没发现什么问题..这次我换成redis ...

  7. 【连载】redis库存操作,分布式锁的四种实现方式[四]--基于Redis lua脚本机制实现分布式锁

    一.redis lua介绍 Redis 提供了非常丰富的指令集,但是用户依然不满足,希望可以自定义扩充若干指令来完成一些特定领域的问题.Redis 为这样的用户场景提供了 lua 脚本支持,用户可以向 ...

  8. redis --- lua 脚本实现原子操作

    如题, 楼主的想法很简单, lua 脚本本身支持原子性, 所以把命令写进一个脚本就行, 当然后续还会优化才能放到生产上,例如缓存脚本 ,redis 本身会缓存执行过的脚本 ,这样速度更快, 再优化, ...

  9. Redis进阶应用:Redis+Lua脚本实现复合操作

    一.引言 Redis是高性能的key-value数据库,在很大程度克服了memcached这类key/value存储的不足,在部分场景下,是对关系数据库的良好补充.得益于超高性能和丰富的数据结构,Re ...

  10. redis>lua脚本

    String lua="local num=redis.call('incr',KEYS[1])\n"+"if tonumber(num)==1 then\n" ...

随机推荐

  1. 鱼和熊掌兼得:C++代码在编译时完成白盒测试

    摘要:如果能够让代码在编译的时候,自动完成白盒测试,这不是天方夜谭. 白盒测试也叫开发者测试,是对特定代码函数或模块所进行的功能测试.当前主流的白盒测试方法是:先针对仿真或者生产环境编译出可执行文件, ...

  2. 轻松带你学习java-agent

    摘要:java-agent是应用于java的trace工具,核心是对JVMTI(JVM Tool Interface)的调用. 本文分享自华为云社区<Java动态trace技术:java-age ...

  3. 华为云IoT设备接入服务全体验

    摘要:华为云IoT设备接入服务,海量设备,一键接入,你值得拥有! 本文分享自华为云社区<[云驻共创]Huawei Mate 40产线直击之 华为云IoT设备接入服务全体验>,原文作者:启明 ...

  4. 顶级加密混淆混淆工具测评:ipagurd

    ​ 顶级加密混淆混淆工具测评:ipagurd 摘要 JavaScript代码安全需求日益增长,因此JavaScript混淆工具的使用变得广泛.本文将对专业.商业JavaScript混淆工具ipagur ...

  5. [BitSail] Connector开发详解系列三:SourceReader

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 Source Connector 本文将主要介绍负责数据读取的组件SourceReader: SourceRead ...

  6. 火山引擎DataTester:小改动带来大收益,A/B实验助力幸福里APP精准优化

      幸福里APP是抖音集团旗下开发运营的集内容.社区.工具于一体的房产信息综合平台,基于个性化推荐引擎向用户推荐优质的房产内容房源信息.本文将介绍幸福里APP应用火山引擎A/B测试DataTester ...

  7. 远程桌面CredSSP 加密数据库修正

    如图所示: 远程桌面连接,出现身份验证错误,要求的函数不受支持,这可能是由于 CredSSP 加密数据库修正

  8. 前端科普系列(2):Node.js 换个角度看世界

    本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/fPNMaeNYgU3eJsh0SLMRRg作者:孔垂亮 [前端科普系列]往期精彩内容: &l ...

  9. 函数计算 HTTP 触发器支持异步,解放双手搭建 Web 服务

    作者| 阿里云Serverless技术专家 澈尔 当前阿里云函数计算支持两种类型的函数:事件函数和 HTTP 函数.其中 HTTP 函数结合 HTTP 触发器,能够支持用户直接通过 HTTP 请求利用 ...

  10. springboot 参数通过 @RequestBody传递的写法

    controller中有时候参数是使用 @RequestBody传递的这种怎么写? 直接上代码 @RequestMapping("/test") public void getAc ...