Redis中的Lua脚本(五)

news/2024/9/23 11:20:13/

Lua脚本

脚本复制

复制EVALSHA命令

EVALSHA命令式所有与Lua脚本有关的命令中,复制操作最复杂的一个,因为主服务器与从服务器载入Lua脚本的情况可能有所不同,所以主服务器不能像复制EVAL命令、SCRIPT LOAD命令或者SCRIPT FLUSH命令那样,直接将EVALSHA命令传播给从服务器,对于一个在主服务器被成功执行的EVALSHA命令来说,相同的EVALSHA命令在从服务器执行时可能会出现脚本未找到(not found)错误。
举个例子。假设现在有一个主服务器master,如果客户端向主服务器发送命令:

127.0.0.1:6379> SCRIPT LOAD "return 'hello world'"
"5332031c6b470dc5a0dd9b4bf2030dea6d65de91"

那么在执行这个SCRIPT LOAD命令之后,SHA1值为5332031c6b470dc5a0dd9b4bf2030dea6d65de91的脚本
就存在于主服务器中了,现在假设一个从服务器slave1开始复制主服务器master,如果master不想办法将脚本:

"return 'hello world'"

传送给slave1载入的话,那么当客户端向主服务器发送命令:

127.0.0.1:6379> EVALSHA "5332031c6b470dc5a0dd9b4bf2030dea6d65de91" 0
"hello world"

的时候,master将成功执行这个EVALSHA命令,而当master将这个命令传播给slave1执行的时候,slave1却会出现脚本未找到错误:

127.0.0.1:6380> EVALSHA "5332031c6b470dc5a0dd9b4bf2030dea6d65de91" 0
(error) NOSCRIPT No matching script. Please use EVAL.

更为复杂的是,因为多个从服务器之间载入Lua脚本的情况也可能各有不同,所以即使一个EVALSHA命令可以在某个从服务器成功执行,也不代表这个EVALSHA命令就一定可以在另一个从服务器成功执行。

例子
  • 举个例子。假设有主服务器master和从服务器slave1,并且slave1一致复制着master,所以master载入的所有Lua脚本,slave1也有载入(通过传播EVAL命令或者SCRIPT LOAD命令来实现)例如说,如果客户端向master发送命令
127.0.0.1:6379> SCRIPT LOAD "return 'hello world'"
"5332031c6b470dc5a0dd9b4bf2030dea6d65de91"

那么这个命令也会被传播到slave1上面,所以master和slave1都会成功载入SHA1校验和为 5332031c6b470dc5a0dd9b4bf2030dea6d65de91
的Lua脚本。如果这时,一个新的从服务器slave2开始复制主服务器master,如果master不想办法将脚本:

"return 'hello world'"

传送给slave2的话,那么当客户端向主服务器发送命令:

127.0.0.1:6379> EVALSHA "5332031c6b470dc5a0dd9b4bf2030dea6d65de91" 0
"hello world"

的时候,master和slave1都将成功执行这个EVALSHA命令,而slave2却会发生脚本未找到错误。为了防止以上假设的情况出现,Redis要求主服务器在传播EVALSHA命令的时候,必须确保EVALSHA命令要执行的脚本已经被所有从服务器载入过,如果不能确保这一点的话,主服务器会将EVALSHA命令转换成一个等价的EVAL命令,然后通过传播EVAL命令来代替EVALSHA命令。传播EVALSHA命令,或者将EVALSHA命令转换成命令,都需要用到服务器状态的lua_scripts字典和repl_scriptcache_dict字典

判断传播EVALSHA命令是否安全的方法

主服务器使用服务器状态的repl_scriptcache_dict字典记录自己已经将哪些脚本传播给了所有从服务器:

struct redisServer{
// ...dict *replc_scriptcache_dict;// ...
};

repl_scriptcache_dict字典的键是一个个Lua脚本的SHA1校验和,而字典的值则全部都是NULL,当一个校验和出现在repl_scriptcache_dict字典时,说ing这个校验和对应的Lua脚本已经传播给了所有从服务器,主服务器
可以直接向从服务器传播包含这个SHA1校验和的EVALSHA命令,而不必担心从服务器会出现脚本未找到错误

例子
  • 举个例子。如果主服务器repl_scriptcache_dict字典的当前状态如图所示。那么主服务器可以向从服务器传播以下三个EVALSHA命令,并且从服务器在执行这些EVAlSHA命令的时候不会出现脚本未找到错误:
EVALSHA "2f31ba2bb6d6a0f42cc159d2e2dad55440778de3" ...
EVALSHA "a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9" ...
EVALSHA "4475bfb5919b5ad16424cb50f74d4724ae833e72" ...

另一方面,如果一个脚本的SHAR1校验和存在于lua_scripts字典,但是不存在于repl_scriptcache_dict字典,那么说明校验和对应的Lua脚本已经被主服务器载入,但是并没有传播给所有从服务器,如果尝试向从服务器传播包含这个SHA1校验和的EVALSHA命令,那么至少有一个从服务器会出现脚本未找到错误
在这里插入图片描述

  • 举个例子。对于如图所示的lua_scirpts字典,以及上图的repl_scriptcache_dict字典来说,SHA1校验和为:
"5332031c6b470dc5a0dd9b4bf2030dea6d65de91"

的脚本:

"return 'hello world'"

虽然存在于lua_scirpts字典,但是repl_scriptcache_dict字典却并不包含校验和"5332031c6b470dc5a0dd9b4bf2030dea6d65de91"
这说明脚本

"return 'hello world'"

虽然已经载入到主服务器里面,但并未传播给所有从服务器,如果主服务器尝试向从服务器发送命令:

EVALSHA "5332031c6b470dc5a0dd9b4bf2030dea6d65de91" ...

那么至少会有一个从服务器遇上脚本未找到错误
在这里插入图片描述


http://www.ppmy.cn/news/1431631.html

相关文章

MATLAB初学者入门(10)—— 粒子群算法

粒子群优化(Particle Swarm Optimization, PSO)是一种基于群体协作的优化技术,它由社会行为模型(如鸟群觅食行为)启发而来。PSO 通过模拟一群粒子(候选解)在解空间中的移动来寻找最优解。每个粒…

力扣HOT100 - 226. 翻转二叉树

解题思路: class Solution {public TreeNode invertTree(TreeNode root) {if (root null) return null;TreeNode left invertTree(root.left);TreeNode right invertTree(root.right);root.left right;root.right left;return root;} }

【Python-正则表达式】

Python-正则表达式 ■ 基础匹配■ match 从头匹配■ search 搜索匹配■ findall 搜索全部匹配■ 综合 ■ 元字符匹配■ r[b-eF-Z3-9] r表示意思■ 正则表达式使用元字符进行匹配■ 匹配账号,只能由字母和数字组成,长度限制6到10位■ 匹配QQ号&#xff0c…

STM32标准库编程与51单片机直接写寄存器的区别和联系

简介: 在学完51单片机之后,我们去学习32的时候,会发现编程的方法有很大的区别,让人非常的不适应,但是通过不断的调用相应外设的库函数之后,你也可以去编程STM32,来实现功能,但是你真…

基于STM32CubeMX的嵌入式开发基础

内部没有上拉电阻,外部就要加一个 上拉或者下拉电阻,最基本上的作用是将状态不确定的信号通过一个电阻将其稳定在高电平或低电平 上拉下拉其实起的是稳定电平的作用 问题:单片机的外围电路设计及程序编写大多是以低电平有效来驱动电路的&…

磐石云外呼系统使用注意事项

磐石云外呼系统是一种基于云计算技术的电话外呼服务,旨在帮助企业提高外呼效率,增强客户沟通和服务能力。在使用过程中,企业需要注意系统的选择、安装、配置、使用方法以及数据安全和合规性等方面的问题。 使用前的准备 在使用磐石云外呼系统…

Android 开机流程

Android12 开机流程 Android开机流程的意义在于确保系统硬件设备的正确初始化、加载操作系统内核、启动系统服务,并最终使应用程序能够正常运行。它是Android系统启动的基础,保证了系统的可靠性和稳定性。 初始化硬件设备:在开机流程中,引导加载程序会初始化硬件设备,包括…

Rust常用特型之From和Into特型

在Rust标准库中,存在很多常用的工具类特型,它们能帮助我们写出更具有Rust风格的代码。 std::convert::From和std::convert::Into特型是一种用于转换的特型,它们会消耗某个类型的值,返回另一个类型的值。相对于AsRef和AsMut特型用来…