Redis脚本调用那点事儿,性能提升其实没那么难说实话
- 问答
- 2025-12-27 11:37:06
- 2
说到用Redis,大家肯定都用过那些基本命令,像SET、GET、HSET什么的,单个命令执行起来很快,但有时候业务逻辑复杂了,你需要一连串操作,比如先检查某个值,然后根据结果去修改另一个值,最后再删掉一个键,这时候要是一个一个命令发过去,一来一回的网络开销就大了,而且每个命令Redis都得单独处理,性能就不是最优的了。
那怎么办呢?Redis提供了一个叫Lua脚本的功能(来源:Redis官方文档对EVAL命令的介绍),你可以把这一连串操作写成一个Lua脚本,然后一次性发给Redis去执行,这就好比你是老板,要吩咐员工做三件事,一种方式是打三次电话,每次说一件事;另一种方式是打一次电话,把三件事一口气说完,显然后者更省时间,对吧?Lua脚本就是那个“一口气说完”的电话。
用Lua脚本最大的好处有几个,它减少了网络开销,本来要发N次命令,现在只需要发一次脚本就行了,尤其是在网络延迟比较高的情况下,这个提升非常明显,也是更重要的一点,Lua脚本在Redis中是原子性执行的(来源:Redis官方文档对脚本原子性的说明),这个词听起来有点专业,但意思很简单:就是在脚本执行的过程中,不会有其他客户端的命令插进来捣乱,脚本会被当成一个整体,要么全部执行成功,要么全部不执行,不会执行到一半被别的操作打断,这对于要求数据一致性的场景特别重要,比如秒杀扣库存,你肯定不希望出现超卖的情况。

刚开始用脚本的时候,很多人可能会犯一个错误:每次执行都直接把脚本的代码字符串发过去,就像这样,每次都要把一整段Lua代码从客户端传到Redis服务器,如果脚本很长,或者执行的频率非常高,那传输脚本本身也会成为新的开销。
Redis早就想到了这一点,所以它有一个脚本缓存和SHA1校验和的机制(来源:Redis官方文档对SCRIPT LOAD和EVALSHA命令的介绍),你可以先把脚本加载到Redis服务器上,Redis会记住这个脚本,并返回给你一个唯一的“指纹”(也就是SHA1哈希值),之后你再需要执行这个脚本的时候,不用传整个脚本代码了,只需要把这个“指纹”和参数发过去就行,Redis一看这个指纹,就知道你要执行哪个缓存的脚本了,这就像你去健身房存包,第一次管理员给你一个手牌,之后你凭手牌取包,就不用再描述你的包长什么样了,这样就大大减少了需要传输的数据量。

那这个“指纹”会一直存在吗?只要你不重启Redis服务器,或者手动清除脚本缓存,它就会一直有效,但为了保险起见,比较常见的做法是,在应用程序启动的时候,先把所有需要用到的脚本都通过SCRIPT LOAD命令加载上去,把返回的SHA1值存下来备用,这样在运行时就能高效地使用EVALSHA来调用了,万一Redis因为某种原因把脚本缓存清掉了(比如服务器重启),EVALSHA命令会返回一个错误,告诉你脚本没找到,这时候你的客户端代码应该能捕获到这个错误,然后退一步,用老的EVAL命令再把脚本代码发一次,并重新缓存SHA1值,这是一种降级策略,确保程序的健壮性。
除了原子性和减少网络开销,Lua脚本还能帮你简化客户端的逻辑,有些复杂的计算或者判断,你可以直接放在Redis服务器端用Lua完成,只把最终结果返回给客户端,客户端就不用先取一堆数据回来,计算完再发回去,这样客户端的代码会变得清爽很多。
写Lua脚本也要注意点事情,最重要的一点是,别在脚本里写太耗时的操作(来源:Redis官方文档对脚本执行时间的警告),因为Redis是单线程处理命令的,你的脚本执行时间太长,会阻塞住所有其他客户端的请求,整个Redis就跟卡住了一样,像什么复杂的循环计算、或者不小心写了个死循环,都是大忌,脚本应该只用来做轻量的数据操作和逻辑判断。
Redis的Lua脚本是个好东西,它把多个操作打包成一个原子操作,既提升了性能(主要是减少网络延迟),又保证了数据一致性,用上脚本缓存机制之后,性能还能更进一步,虽然需要学一点简单的Lua语法,但这个学习成本比起它带来的收益来说,是非常值得的,性能提升这事儿,有时候就是找到这些关键点,用对方法,效果立竿见影,说实话,真的没那么难。
本文由歧云亭于2025-12-27发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/69385.html
