当前位置: 首页 > news >正文

记一次通过脚本来实现自定义容器的自动重启

通过脚本来实现自定义容器的自动重启

  • 1. 场景还原
  • 2. 自定义启动脚本
  • 3. 使用自定义脚本来作为容器启动的脚本
  • 4. 制作自定义脚本作为入口点的新镜像
  • 5. 测试新镜像启动是否走自定义启动脚本

1. 场景还原

现在我有一个自定义的Docker镜像,是基于基础镜像来构建的带有多个服务的镜像,镜像里面包含了两个服务,其中需要A服务先启动,然后B服务依赖A服务,需要等A服务启动成功后,才能正常对外提供服务。其中A服务启动成功后,可以通过 5005 端口来判断,A服务的端口就是 5005;

在刚开始使用的时候,每次都是先启动一个这个镜像的容器,然后进入容器内部,手动执行A服务的启动命令,然后等待A服务启动完成,再执行B服务的启动命令。

这种场景,如果在服务器不关机的情况下,服务一直是正常运行的。但是如果服务器关机重启了,或者需要更新镜像版本了,这就得人工来重复操作了。这就显得有点不太智能了,于是想着折腾一番,能不能整一个在容器启动的时候,执行某个脚本,这个启动脚本里面包含A服务、B服务的启动命令,并且还能维护下启动顺序,如果能把启动服务的日志输出到Docker容器的日志里,使用 docker logs 命令能实时的查看服务的日志,这样也是极好的。于是带着这个目的,开始折腾了。

2. 自定义启动脚本

针对上面的场景,先写一个shell脚本,来启动需要启动的服务;
其中 A服务的启动命令是:

rasa run --enable-api

A服务启动成功后,可以对外提供 5005 端口的 web服务;但是 A服务的启动过程有点慢,比如要几十秒或者一分钟,这个时间不确定;

B服务的启动命令是:

python3 /home/rasa_dev/bot_api.py

B服务启动成功后,可以对外提供 5006 端口的 web服务;

自定义脚本 wait_for_port.sh 内容如下:

#!/bin/bash# 第一步:运行 rasa run --enable-api 命令
nohup rasa run --enable-api &# 第二步:等待端口5005可用
while ! nc -z localhost 5005; doecho "Waiting for port 5005 to become available..."sleep 5
done# 第三步:一旦端口可用,执行 bot_api.py
python3 /home/rasa_dev/bot_api.py &# 防止容器退出
sleep infinity
[root@VM-0-5-centos aikg-bot_build]# 

脚本包含了需要启动的命令,并且有个判断A服务 5005端口的过程,在端口可用之后再启动 B 服务

在这个脚本中,nc(netcat)命令用于检查端口是否可访问。while循环将持续检测端口,直到它变为可访问状态。一旦端口可用,脚本将执行bot_api.py

刚开始我将上面两个启动命令的日志重定向到 /logs 文件夹下、比如 启动 B服务的命令为:

python3 /home/rasa_dev/bot_api.py >> /logs/bot_api.log 2>&1 &

这样在 B服务启动时,启动日志就会追加到 /logs/bot_api.log 文件中了。

然后启动镜像的时候将日志目录挂载出来,这样就可以在宿主机上查看服务的启动日志了,但是我还是感觉麻烦,所以又改成了上面的命令,移除了/logs/bot_api.log 2>&1 这个日志重定向的内容,这样就不会将日志重定向到文件,而是直接输出到stdoutstderr。当容器运行时,所有输出都会被捕获,这样就可以使用docker logs命令来查看它们:

docker logs <container-name-or-id>

如果日志文件很重要,需要留痕或者方便后面追溯的话,可以将日志重定向到文件中,这样方便追溯或者排查原因,不过不考虑日志内容丢失的话,直接输出到stdoutstderr是最简便的方式。

刚开始我的镜像里面是不包含 nc 这个命令的,我先使用当前版本的镜像,启动一个容器,然后进入容器内部安装这个nc命令:

比如我之前的镜像是:test-bot:1.0.0 ,使用下面命令直接启动一个容器:

docker run -itd --name test-bot x-bot:1.0.0 /bin/bash

上面命令已交互式的方式来运行一个容器,容器启动后,自动进入容器内部,接着来安装这个 nc工具;

这里需要检查下基础镜像底层是Centos还是Ubuntu或者其他的基础镜像,这个决定我们接下来要如何安装新的工具。

可以直接运行 yum 命令 或者 apt-get 命令,看下哪个可以正常运行,则接下来用哪个命令来安装 nc 工具;

我这里支持 apt-get 的方式来安装:

root@aikg-bot-build:/home/rasa_dev# yum
bash: yum: command not found
root@aikg-bot-build:/home/rasa_dev# 
root@aikg-bot-build:/home/rasa_dev# apt-get
apt 1.8.2.3 (amd64)
Usage: apt-get [options] commandapt-get [options] install|remove pkg1 [pkg2 ...]apt-get [options] source pkg1 [pkg2 ...]apt-get is a command line interface for retrieval of packages
and information about them from authenticated sources and
for installation, upgrade and removal of packages together
with their dependencies.

如果是支持 yum 命令的话,执行 yum 命令,应该是:

[root@VM-0-5-centos ~]# yumFile "/usr/bin/yum", line 30except KeyboardInterrupt, e:^
SyntaxError: invalid syntax
[root@VM-0-5-centos ~]# 
[root@VM-0-5-centos ~]# apt-get
-bash: apt-get: command not found
[root@VM-0-5-centos ~]# 

安装 nc 工具的话,直接在容器内执行:apt-get update && apt-get install -y netcat

在执行 apt-get install 之前,通常建议先执行 apt-get update,主要有以下几个原因:

  • 更新软件包列表:
    apt-get update 命令会从配置的源服务器下载最新的软件包列表。这些列表包含了每个软件包的最新版本和依赖关系信息。通过更新这些列表,你的系统就能够获取到当前最新的软件包信息。

  • 确保安装最新版本的软件:
    如果不执行 apt-get update,你的系统可能仍然使用旧的软件包列表,这意味着你可能无法安装到最新版本的软件包。在这种情况下,执行 apt-get install 可能会安装旧版本的软件包,甚至可能会导致安装失败或出现依赖性问题。

  • 解决依赖关系:
    软件包之间可能有复杂的依赖关系,新的软件包版本可能会改变这些依赖关系。通过执行 apt-get update,你能确保所有依赖关系都基于最新的信息,从而避免在安装过程中遇到问题。

  • 安全性:
    最新的软件包列表通常包括了最新的安全修复。如果你不更新列表,可能会错过一些重要的安全更新,导致系统存在潜在的安全风险。

  • 系统稳定性:
    最新的软件包列表还包含了各种错误修复和改进,通过保持列表的更新,可以提高系统的稳定性和性能。

一个典型的软件包安装流程如下:

sudo apt-get update          # 更新软件包列表
sudo apt-get upgrade         # 升级已安装的软件包(可选)
sudo apt-get install <package-name>  # 安装新的软件包

这样做可以确保你安装的是最新版本的软件包,并且系统依赖关系是最新的,减少安装过程中遇到问题的可能性。

总的来说,执行 apt-get update 是一个确保安装过程顺利并且系统安全和稳定的好习惯。

上面工具安装完成,可以先测试下,是否能正常执行

root@aikg-bot-build:/home/rasa_dev# nc -zv localhost 80
localhost [127.0.0.1] 80 (http) : Connection refused
root@aikg-bot-build:/home/rasa_dev# 
root@aikg-bot-build:/home/rasa_dev# nc -zv localhost 5005
localhost [127.0.0.1] 5005 (?) open
root@aikg-bot-build:/home/rasa_dev#

可以看到当运行 nc -zv localhost 80,得到了 “Connection refused” 的消息。这意味着端口80上没有服务正在监听。

当运行 nc -zv localhost 5005,得到了 “open” 的消息,这表示端口5005上有一个服务正在监听。这通常意味着有一个服务(可能是某个应用或某个后台服务)正在使用这个端口。

nc-v 选项提供了详细的输出,这有助于诊断网络连接问题。当它说 “open” 或者 “Connection refused”,它实际上是在告诉你 nc 尝试与指定端口建立连接的结果。如果端口是开放的,nc 能够成功建立连接;如果端口被拒绝连接,那通常意味着没有服务在那里监听,或者防火墙阻止了连接。

这里还有一个小 tips 就是脚本的最后一行:sleep infinity,刚开始没有加这个得时候,我发现容器启动完成后,就自动 Down 掉了,并不能一直停留在启动成功的状态。

解决这个问题呢,有两种方式,其目的就是让启动脚本在启动服务完成后,进入一个无限循环的状态,一直来维持住现状。

  • 方式一:使用tail -f /dev/null
    tail -f /dev/null命令会让脚本进入一个无限循环,读取/dev/null文件的末尾,实际上什么也不做,但是这会保持一个前台进程运行,从而防止容器因缺乏前台进程而自动退出。
  • 方式二:使用 sleep infinity
    sleep infinity表示让脚本进入无限期睡眠,这样即使所有其他命令都已完成,容器也不会退出;

3. 使用自定义脚本来作为容器启动的脚本

由于这里要修改镜像的启动命令,就得需要重新构建一个新的镜像了,先整个 Dockerfile,内容如下:

[root@VM-0-5-centos ~]# cat Dockerfile 
FROM test-bot:1.0.0LABEL MAINTAINER="linmm"# 设置工作目录
WORKDIR /home/rasa_dev# 定义环境启动时执行的脚本
ADD wait_for_port.sh /wait_for_port.sh
RUN chmod +x /wait_for_port.sh# 设置 ENTRYPOINT 和 CMD
ENTRYPOINT ["/wait_for_port.sh"][root@VM-0-5-centos aikg-bot_build]# 

这里我们自定义的脚本 wait_for_port.sh 其实内容很简单,只包含几个固定的命令,没有涉及到动态的参数什么的。

如果复杂一点,脚本里面需要动态参数,比如要监听的端口 5005 是动态的,这样就可以在 Dockerfile 文件的最后,来使用 CMD 命令来给脚本传入参数;

比如在文件的最后一行添加内容:CMD ["5005"]

CMD指令提供了容器启动时ENTRYPOINT所指定的命令需要的参数。这里,CMD指定了参数5005,这通常会被传递给ENTRYPOINT指定的脚本作为参数使用。

如果wait_for_port.sh不需要额外参数,那么CMD指令可以省略,或者可以设置成CMD []表示没有参数。

4. 制作自定义脚本作为入口点的新镜像

现在自定义脚本也有了,Dockerfile 也有了,那就开整新镜像吧。

[root@VM-0-5-centos test-bot_build]# ll
-rw-r--r-- 1 root root      286 Jun 20 19:40 Dockerfile
-rwxr--r-- 1 root root      360 Jun 19 17:50 wait_for_port.sh
[root@VM-0-5-centos aikg-bot_build]#

直接在当前目录下执行:

[root@VM-0-5-centos aikg-bot_build]# docker build -t test-bot:1.0.1 .
Sending build context to Docker daemon  61.07MB
Step 1/6 : FROM test-bot:1.0.3_r3_1---> f6d10507d2f2
Step 2/6 : LABEL MAINTAINER="linmm"---> Running in 5a9275d08c2e
Removing intermediate container 5a9275d08c2e---> 91ee1346c000
Step 3/6 : WORKDIR /home/rasa_dev---> Running in 25a410ccf9f9
Removing intermediate container 25a410ccf9f9---> 18b42a453605
Step 4/6 : ADD wait_for_port.sh /wait_for_port.sh---> cf6136d5fa86
Step 5/6 : RUN chmod +x /wait_for_port.sh---> Running in 12a6ba7675b3
Removing intermediate container 12a6ba7675b3---> f6e9e1cbd2d7
Step 6/6 : ENTRYPOINT ["/wait_for_port.sh"]---> Running in 18ea0cd27bc4
Removing intermediate container 18ea0cd27bc4---> 0c8e946b6409
Successfully built 0c8e946b6409
Successfully tagged test-bot:1.0.1

新镜像顺利构建完成。

5. 测试新镜像启动是否走自定义启动脚本

直接运行

docker run -itd --name test-bot x-bot:1.0.1 

接着使用 docker logs 命令来查看启动日志:

[root@VM-0-5-centos ~]# docker logs -f --tail 20  test-bot
Waiting for port 5005 to become available...
/usr/local/lib/python3.10/site-packages/rasa/core/tracker_store.py:1042: MovedIn20Warning: Deprecated API features detected! Base: DeclarativeMeta = declarative_base()
/usr/local/lib/python3.10/site-packages/rasa/shared/utils/validation.py:134: DeprecationWarning: pkg_resources is deprecatedimport pkg_resources
2024-06-20 12:31:53 INFO     root  - Starting Rasa server on http://0.0.0.0:5005
2024-06-20 12:31:54 INFO     rasa.core.processor  - Loading model models/nlu-20240620-122934-future-sharp.tar.gz...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...rasa.shared.utils.io.raise_warning(
2024-06-20 12:32:32 INFO     root  - Rasa server is up and running.* Serving Flask app 'bot_api'* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.* Running on all addresses (0.0.0.0)* Running on http://127.0.0.1:5006* Running on http://172.27.100.24:5006
Press CTRL+C to quit

可以看到容器启动后,限制行了启动A服务,在 A服务启动完成前,通过监听 5005 端口来循环阻塞,接着再启动 B服务;并且容器不会自动停止。

相关文章:

记一次通过脚本来实现自定义容器的自动重启

通过脚本来实现自定义容器的自动重启 1. 场景还原2. 自定义启动脚本3. 使用自定义脚本来作为容器启动的脚本4. 制作自定义脚本作为入口点的新镜像5. 测试新镜像启动是否走自定义启动脚本 1. 场景还原 现在我有一个自定义的Docker镜像&#xff0c;是基于基础镜像来构建的带有多…...

基于Django、Bootstrap的电影推荐系统,算法基于用户的协同过滤算法,有爬虫有可视化后台

背景 基于Django和Bootstrap的电影推荐系统结合了用户协同过滤算法&#xff0c;通过爬虫技术获取电影数据&#xff0c;并在可视化后台展示推荐结果。该系统旨在提供个性化的电影推荐服务&#xff0c;帮助用户发现符合其喜好的电影。 用户协同过滤算法是一种常用的推荐算法&am…...

mysql、mariadb 登录主机的含义,如何修改登录主机,如何删除登录主机

MariaDB版本: 10.3.39 登录主机的含义&#xff1a; 参考 1 阿风说事&#xff1a;说世间百态、聊奇闻趣事&#xff0c;分享个人观点和独到见解 2 mysql授权localhost&%区别及一直授权错误解决办法&#xff08;安装openstack有感&#xff09; 3 ERROR 1396 (HY000): Operat…...

c++ 设计模式 的课本范例

&#xff08;1&#xff09; 框架设计模式 model mode &#xff1a; 算法的框架不变&#xff0c;算法的细节可以改变。主要依赖多态。 class Player { protected:int life;int magic;int attack;virtual void effect_self() {}virtual void effect_enemy() {}virtual bool can_…...

QT中绘制点阵

1.QGraphicsScene&#xff0c;QGraphicsView&#xff0c;QGraphicsItem机制 #include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> #include <QGraphicsEllipseItem>int main(int argc, char *argv[]) {QApplication app(arg…...

机器人里程计(Odometry)

机器人里程计&#xff08;Odometry&#xff09;是机器人定位和导航中的一个关键概念&#xff0c;它涉及到利用传感器数据来估计机器人在环境中的位置和姿态。里程计的基本原理是根据机器人自身动作的反馈来计算其相对于初始位置的位移。这通常包括机器人从一个已知位置开始&…...

后端实现预览pdf,mp4,图片

PDF预览 /*** pdf预览* param response*/RequestMapping(value "/preview")public void showPdf(HttpServletResponse response) {try {//String filePath this.getClass().getClassLoader().getResource("../../static/pdf/readme.pdf").getPath();Stri…...

【C++】数据类型、函数、头文件、断点调试、输入输出、条件与分支、VS项目设置

四、基本概念 这部分和C语言重复的部分就简写速过&#xff0c;因为我之前写过一个C语言的系列&#xff0c;非常详细。C和C这些都是一样的&#xff0c;所以这里不再一遍遍重复码字了。感兴趣的同学可以翻看我之前的C语言系列文章。 1、数据类型 编程的本质就是操作数据。 操…...

Spring框架的原理及应用详解(六)

本系列文章简介: 在当今的软件开发世界中,随着应用复杂性的不断增加和技术的快速发展,传统的编程方式已经难以满足快速迭代、高可扩展性和易于维护的需求。为此,开发者们一直在寻求更加高效、灵活且易于管理的开发框架,以帮助他们应对这些挑战。Spring框架就是在这样的背景…...

C++ | Leetcode C++题解之第151题反转字符串中的单词

题目&#xff1a; 题解&#xff1a; class Solution { public:string reverseWords(string s) {int left 0, right s.size() - 1;// 去掉字符串开头的空白字符while (left < right && s[left] ) left;// 去掉字符串末尾的空白字符while (left < right &…...

Leetcode 415. 字符串相加-大数相加

415. 字符串相加 - 力扣&#xff08;LeetCode&#xff09; class Solution {/**2024.6.17大数相加&#xff0c;从2个字符串最后一位开始加&#xff0c;如果没遍历到下标0&#xff0c;就一直遍历&#xff0c;减去‘a’得到数值&#xff0c;循环结束条件就是 字符串1遍历完了&am…...

IDEA集成Docker实现快捷部署

本文已收录于专栏 《运维》 目录 背景介绍优势特点操作步骤一、修改Docker配置二、配置Docker插件三、编写Maven插件四、构建Docker镜像五、创建Docker容器 总结提升 背景介绍 在我们手动通过Docker部署项目的时候&#xff0c;都是通过把打包好的jar包放到服务器上并且在服务器…...

五十四、openlayers官网示例LineString Arrows解析——在地图上绘制箭头

官网demo地址&#xff1a; LineString Arrows 这篇介绍了在地图上绘制箭头。 创建一个矢量数据源&#xff0c;将其绑定为draw的数据源并展示在矢量图层上。 const source new VectorSource();const vector new VectorLayer({source: source,style: styleFunction,});map.ad…...

内核学习——3、自旋锁的作用及其实现

作用&#xff1a; 保护一段临界区的操作时独占的&#xff0c;不能由其他cpu或者线程同时访问破坏数据结构多核系统SMP&#xff1a; 主要考虑一个cpu进入临界区之后&#xff0c;其他CPU不能再去进入这个临界代码区单核系统&#xff1a; 不能被其他进程抢占单核系统自旋锁实现&am…...

恒昌公益第五所“云杉校园”于湖南怀化正式揭牌

在中国近代史上湖南无疑是不可忽视的存在&#xff0c;在“敢为天下先”的湖湘文化熏陶下更是涌现了无数改变国家命运的人物。而作为推动民族复兴与社会进步的关键支柱&#xff0c;重视教育的传统起到的作用功不可没。在迈向中国式现代化的当下&#xff0c;积极推动优质教育资源…...

番外篇 | YOLOv8算法解析和实战应用:车辆检测 + 车辆追踪 + 行驶速度计算

前言:Hello大家好,我是小哥谈。YOLOv8是ultralytics公司在2023年1月10号开源的,是YOLOv5的下一个重大更新版本,目前支持图像分类、物体检测和实例分割任务,在还没有开源时就收到了用户的广泛关注。它是一个SOTA模型,建立在以前YOLO版本的成功基础上,并引入了新的功能和改…...

【React】useState 的原理

useState 是 React Hooks 中的一个核心函数,用于在函数组件中添加和管理状态。以下是 useState 的原理及其工作方式的详细解释: 1. 基本概念 useState 允许你在函数组件中添加 state。它接受一个参数,这个参数是 state 的初始值。useState 返回一个包含两个元素的数组: 第…...

从二元一次方程组到二阶行列式再到克拉默法则

目录 引言1 二元一次方程组什么是二元一次方程组&#xff1f;解法概述示例1. 操作步骤2. 消元法 2 二阶行列式引入行列式行列式定义示例计算 3 克拉默法则什么是克拉默法则&#xff1f;克拉默法则公式使用克拉默法则求解 4 总结 引言 在数学中&#xff0c;线性代数提供了一套强…...

示例:WPF中绑定枚举到ComboBox想显示成中文或自定义名称如何实现

一、目的&#xff1a;在开发过程中绑定的枚举不想显示成英文字段怎么办&#xff0c;这里通过TypeConverter的方式来实现绑定的枚举从定义的特性中读取 二、实现 首先定义如下枚举 [TypeConverter(typeof(DisplayEnumConverter))]public enum MyEnum{[Display(Name "无&q…...

嵌入式系统软件架构设计方法

1.嵌入式系统软件架构设计的目的 嵌入式系统软件架构是开发大型嵌入式系统密集型软件贯穿始终的关键桥梁&#xff0c;同时软件架构也是软件开发的基础。架构设计的目的是&#xff1a; 保证应用的代码逻辑清晰&#xff0c;避免重复的设计&#xff1b;实现软件的可移植性&#…...

【面试题】风险评估和应急响应的工作流程

风险评估和应急响应是网络安全管理中两个重要的环节。下面分别介绍它们的工作流程&#xff1a; 一、风险评估工作流程&#xff1a; 1.确定评估范围&#xff1a;明确需要评估的信息系统或资产的范围。 2.资产识别&#xff1a;识别并列出所有需要评估的资产&#xff0c;包括硬件…...

Vue70-路由的几个注意点

一、路由组件和一般组件 1-1、一般组件 1-2、路由组件 不用写组件标签。靠路由规则匹配出来&#xff0c;由路由器渲染出来的组件。 1-3、注意点1 一般组件和路由组件&#xff0c;一般放在不同的文件夹&#xff0c;便于管理。 一般组件放在components文件夹下。 1-4、注意点…...

Aidlux 1.4 部署Nextcloud 2024.6实录 没成功

Aidux阉割版Debain10&#xff0c;坑很多&#xff0c;比如找不到实际的系统日志&#xff0c;有知道的大神吗&#xff1f; 1 Apache2安装 # 测试Apache2 sudo apt update && sudo apt upgrade sudo apt install apache2 -y80端口疑似被禁止只能换端口 rootlocalhost:/…...

网络与协议安全复习 - 电子邮件安全

文章目录 PGP(Pretty Good Privacy)功能 S/MIME(Secure/Multipurpose Internet Mail Extensions)DKIM(Domain Keys Identified Mail) PGP(Pretty Good Privacy) 使用符号&#xff1a; Ks&#xff1a;会话密钥、KRa&#xff1a;A 的私钥、KUa&#xff1a;A 的公钥、EP&#xff…...

Python里的序列化是什么?

在Python中&#xff0c;序列化&#xff08;serialization&#xff09;是一个过程&#xff0c;它可以将数据结构或对象状态转换为可以存储或传输的形式。通常&#xff0c;这意味着将数据结构或对象转换为字节流&#xff0c;以便可以将其写入文件、发送到网络&#xff0c;或用于其…...

自动抓取服务器功耗

以下脚本为linux系统内通过ipmitool工具自动抓取服务器当前功耗&#xff0c;每隔5分钟抓取一次&#xff0c;累计抓取20次 脚本如下&#xff1a; #!/bin/bashcurrent_dirpwd node_list${current_dir}/nodelistbmc #BMC IP usernameAdministrator #BMC用…...

服务器接收苹果订阅通知

我们的服务器需要提供一个URL来接收苹果的通知&#xff0c;要使用HTTPS。 苹果会对这个URL发送HTTP POST请求&#xff0c;body是JSON格式&#xff0c;包含了通知的内容。 我们服务器处理成功后&#xff0c;应向苹果返回HTTP 200。若出现问题&#xff0c;需要苹果重新发送通知…...

2024年旅游与经济发展国际会议(ICTED 2024)

2024年旅游与经济发展国际会议&#xff08;ICTED 2024&#xff09; 2024 International Conference on Tourism and Economic Development 【重要信息】 大会地点&#xff1a;青岛 大会官网&#xff1a;http://www.icicted.com 投稿邮箱&#xff1a;icictedsub-conf.com 【注意…...

【NLP练习】Transformer实战-单词预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 任务&#xff1a;自定义输入一段英文文本进行预测 一、定义模型 from tempfile import TemporaryDirectory from typing import Tuple from torch import nn…...

使用Lua脚本保证原子性的Redis分布式锁实现

这是原来的代码&#xff1a; Override public void unlock() {// 获取线程标示String threadId ID_PREFIX Thread.currentThread().getId();// 判断标示是否一致String id stringRedisTemplate.opsForValue().get(KEY_PREFIX name);if (threadId.equals(id)) {// 释放锁st…...