其中第2步是完全在服务器端执行,根据Redis官网的描述:
Redis uses the same Lua interpreter to run all the commands. Also Redis guarantees that a script is executed in an atomic way: no other script or Redis command will be executed while a script is being executed.在Redis Server中执行Lua脚本是一个原子性的操作,时间戳较旧的数据会自动放弃更新缓存数据,因此就可以保证存入缓存中的数据永远是最新的,因此也就解决了数据并发更新时老数据被新数据覆盖的问题。
Lua脚本内部逻辑可以用伪代码描述为:
timestamp=Redis.call('获取时间戳的指令') if (timestamp==nil) then Redis.call('执行更新') elseif (时间戳>timestamp) then Redis.call('执行更新') end使用Lua脚本的调用示意图:
发送脚本 Caller ----------------------------------------> Redis 为脚本创建 Lua 函数 Redis ----------------------------------------> Lua 绑定超时处理钩子 Redis ----------------------------------------> Lua 执行脚本函数 Redis ----------------------------------------> Lua 返回函数执行结果(一个 Lua 值) Redis <---------------------------------------- Lua 将 Lua 值转换为 Redis 回复 并将结果返回给客户端 Caller <---------------------------------------- Redis 总结Redis中进行原子化操作有两个方法:Redis事务或Lua脚本。使用Redis事务只能满足数据在未发生变化进行更新而发生变化就放弃更新的场景。对于实时数据的处理场景来说,Redis的事务无法满足根据时间戳进行业务处理的需要。由于Redis执行Lua脚本时是原子化的并且脚本内部可以编写读写判断逻辑,因此可以借助Lua脚本完成实时数据更新的业务需要。
虽然使用Lua脚本可以较好的满足业务需要,但是在使用Redis脚本时也有一定的注意事项,Lua脚本中不要编写太复杂的操作,应该以尽量简单的逻辑完成整个操作过程,避免因为脚本的执行产生阻塞效应。
参考资料