- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章利用consul在spring boot中实现分布式锁场景分析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
因为在项目实际过程中所采用的是微服务架构,考虑到承载量基本每个相同业务的服务都是多节点部署,所以针对某些资源的访问就不得不用到用到分布式锁了.
这里列举一个最简单的场景,假如有一个智能售货机,由于机器本身的原因不能同一台机器不能同时出两个商品,这就要求在在出货流程前针对同一台机器在同一时刻出现并发创建订单时只能有一笔订单创建成功,但是订单服务是多节点部署的,所以就不得不用到分布式锁了.
以上只是一种简单的业务场景,在各种大型互联网实际应用中,需要分布式锁的业务场景会更多,综合比较了业界基于各种中间件来实现的分布式锁方案,然后结合实际业务最终决定采用consul来实现,因为我们的项目中采用了consul做注册中心,并且consul天生可以保证一致性(这点类似zk),当然zk也能实现分布式锁,但是这里不对这点做过多讨论.
redis虽然也能实现分布式锁,但是可能因为场景比较复杂,如果redis采用cluster部署的话,如果某一主节点出现故障的话,有一定几率会出现脑裂现象,这样就可能会让竞争者在并发时同时获得到锁,这样可能会破坏掉后面的业务,当然出现这种情况的概率很低,但是也不能完全排除,因为redis的根本不能保证强一致性导致的.
好了,这里说的最简单的分布式锁的意思是,多个竞争者同一时间并发去获得锁时,获取失败的就直接返回了,获取成功的继续后续的流程,然后在合适的时间释放锁,并且为锁加了超时时间,防止获得到锁的进程或线程在未来得及释放锁时自己挂掉了,导致资源处于一直被锁定的状态无法得到释放。主要的实现逻辑就是这样,如果有人想实现获得锁失 。
败的竞争者一直继续尝试获得,可以基于该示例进行修改,加上自旋逻辑就OK.
以下是锁实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
package
com.lyb.consullock;
import
com.ecwid.consul.v1.ConsulClient;
import
com.ecwid.consul.v1.agent.model.NewCheck;
import
com.ecwid.consul.v1.kv.model.PutParams;
import
com.ecwid.consul.v1.session.model.NewSession;
import
com.ecwid.consul.v1.session.model.Session;
import
lombok.Data;
import
java.time.LocalDateTime;
import
java.util.ArrayList;
import
java.util.List;
public
class
DistributedLock{
private
ConsulClient consulClient;
/**
* 构造函数
* @param consulHost 注册consul的client或服务端的Ip或主机名,或域名
* @param consulPort 端口号
*/
public
DistributedLock(String consulHost,
int
consulPort){
consulClient =
new
ConsulClient(consulHost,consulPort);
}
/**
* 获得锁的方法
* @param lockName 竞争的资源名
* @param ttlSeconds 锁的超时时间,超过该时间自动释放
* @return
*/
public
LockContext getLock(String lockName,
int
ttlSeconds){
LockContext lockContext =
new
LockContext();
if
(ttlSeconds<
10
|| ttlSeconds >
86400
) ttlSeconds =
60
;
String sessionId = createSession(lockName,ttlSeconds);
boolean
success = lock(lockName,sessionId);
if
(success ==
false
){
consulClient.sessionDestroy(sessionId,
null
);
lockContext.setGetLock(
false
);
return
lockContext;
}
lockContext.setSession(sessionId);
lockContext.setGetLock(
true
);
return
lockContext;
}
/**
* 释放锁
* @param sessionID
*/
public
void
releaseLock(String sessionID){
consulClient.sessionDestroy(sessionID,
null
);
}
private
String createSession(String lockName,
int
ttlSeconds){
NewCheck check =
new
NewCheck();
check.setId(
"check "
+lockName);
check.setName(check.getId());
check.setTtl(ttlSeconds+
"s"
);
//该值和session ttl共同决定决定锁定时长
check.setTimeout(
"10s"
);
consulClient.agentCheckRegister(check);
consulClient.agentCheckPass(check.getId());
NewSession session =
new
NewSession();
session.setBehavior(Session.Behavior.RELEASE);
session.setName(
"session "
+lockName);
session.setLockDelay(
1
);
session.setTtl(ttlSeconds +
"s"
);
//和check ttl共同决定锁时长
List<String> checks =
new
ArrayList<>();
checks.add(check.getId());
session.setChecks(checks);
String sessionId = consulClient.sessionCreate(session,
null
).getValue();
return
sessionId;
}
private
boolean
lock(String lockName,String sessionId){
PutParams putParams =
new
PutParams();
putParams.setAcquireSession(sessionId);
boolean
isSuccess = consulClient.setKVValue(lockName,
"lock:"
+ LocalDateTime.now(),putParams).getValue();
return
isSuccess;
}
/**
* 竞争锁时返回的对象
*/
@Data
public
class
LockContext{
/**
* 获得锁成功返回该值,比便后面用该值来释放锁
*/
private
String session;
/**
* 是否获得到锁
*/
private
boolean
isGetLock;
}
}
|
pom文件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<project xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0
.
0
</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>
2.1
.
6
.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lyb</groupId>
<artifactId>consul-lock</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
<name>consul-lock</name>
<description>Demo project
for
Spring Boot</description>
<properties>
<java.version>
1.8
</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>
1.18
.
8
</version>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>
import
</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
|
测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
package
com.lyb.consullock;
import
org.junit.Assert;
import
org.junit.Test;
import
org.junit.runner.RunWith;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.context.SpringBootTest;
import
org.springframework.test.context.junit4.SpringRunner;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.TimeUnit;
@RunWith
(SpringRunner.
class
)
@SpringBootTest
public
class
ConsulLockApplicationTests {
@Autowired
private
ServiceConfig serviceConfig;
@Test
public
void
lockSameResourer() {
//针对相同资源在同一时刻只有一个线程会获得锁
ExecutorService threadPool = Executors.newFixedThreadPool(
10
);
for
(
int
a=
0
;a<
20
;a++){
threadPool.submit(
() -> {
for
(
int
i =
0
;i <
100
; i++) {
DistributedLock lock =
new
DistributedLock(
serviceConfig.getConsulRegisterHost(),
serviceConfig.getConsulRegisterPort());
DistributedLock.LockContext lockContext = lock.getLock(
"test lock"
,
10
);
if
(lockContext.isGetLock()) {
System.out.println(Thread.currentThread().getName() +
"获得了锁"
);
try
{
TimeUnit.SECONDS.sleep(
1
);
lock.releaseLock(lockContext.getSession());
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
else
{
//System.out.println(Thread.currentThread().getName() + "没有获得锁");
}
}
});
}
try
{
TimeUnit.MINUTES.sleep(
2
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
@Test
public
void
lockDiffResource(){
//针对不通的资源所有线程都应该能获得锁
ExecutorService threadPool = Executors.newFixedThreadPool(
10
);
for
(
int
a=
0
;a<
20
;a++){
threadPool.submit(
() -> {
for
(
int
i =
0
;i <
100
; i++) {
DistributedLock lock =
new
DistributedLock(
serviceConfig.getConsulRegisterHost(),
serviceConfig.getConsulRegisterPort());
DistributedLock.LockContext lockContext = lock.getLock(
"test lock"
+Thread.currentThread().getName(),
10
);
if
(lockContext.isGetLock()) {
System.out.println(Thread.currentThread().getName() +
"获得了锁"
);
try
{
TimeUnit.SECONDS.sleep(
1
);
lock.releaseLock(lockContext.getSession());
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
else
{
//System.out.println(Thread.currentThread().getName() + "没有获得锁");
Assert.assertTrue(lockContext.isGetLock());
}
}
});
}
try
{
TimeUnit.MINUTES.sleep(
2
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
|
项目路径:
https://github.com/wenwuxianren/consul-lock 。
到此这篇关于利用consul在spring boot中实现最简单的分布式锁的文章就介绍到这了,更多相关spring boot分布式锁内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/wenwuxianren/p/11181786.html 。
最后此篇关于利用consul在spring boot中实现分布式锁场景分析的文章就讲到这里了,如果你想了解更多关于利用consul在spring boot中实现分布式锁场景分析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有人可以解释一下 spring-boot-parent 和 spring-boot-starter-parent 之间的区别吗,正如我在下面附加的 GIT HUB 代码链接之一中看到的,他们为 spr
我有与 jersey 框架集成的 Spring Boot 应用程序。 现在,当我尝试运行该应用程序时,它只是停留在 Spring 启动徽标上,之后没有任何 react 。 我也尝试添加 -X ,但徽标
我指的是 Spring Boot 关于 的文档自动配置 和 执行器 模块: 自动配置: Spring Boot AutoConfiguration attempts to automatically
我正在尝试将 apache log4j 集成到我的 Spring boot 应用程序中。这是我的 build.gradle 文件: build.gradle buildscript { rep
使用 Spring Boot Maven 插件的以下命令在生产中启动 Spring Boot 应用程序是否是一个好主意或实践? mvn spring-boot:run 最佳答案 不,这是个坏主意。 您
据我所知,spring boot 和 spring session 为我们提供了一站式自动配置,但是当我的应用程序使用 session redis 和应用程序缓存 redis 时,不是同一个 redi
我希望使用Spring Boot创建一个新的Web应用程序。不幸的是,我的服务器在技术堆栈方面相当有限。它安装了Java 5。 谁能告诉我spring boot是否可以在Java 1.5上运行以及什么
我有3个实体 CarWash(设置Wash) Wash(car_wash_id FK到CarWash) WashComment(wash_id FK到Wash) 有什么办法可以写这个查询 @Qu
我一直在关注this文章。 我正在尝试在Spring-boot应用程序中优雅地处理gRPC错误,的主要目标是能够在gRPC客户端中获取错误状态。 在上面的文章之后,我坚持为异常添加拦截器。如何在Spr
我有一个要使用的自定义log4j布局插件。在IntelliJ中运行或与./gradlew bootRun一起运行时,插件可以正常工作。不使用./gradlew bootJar构建启动jar。 启用-D
我想在给定范围 (5001-5100) 的随机端口上启动 Spring Cloud 应用程序(Spring Boot 1.5.14,Spring Cloud Edgware.SR4)。我知道我们可以使
任何人都可以向我展示或指出不使用 spring boot gradle 插件的 spring boot gradle 项目。 我正在寻找类似不使用 gradle 插件的 spring boot sta
我当时尝试包含上述依赖项之一,但找不到任何区别: spring boot starter web:我可以看到 Flux 和 Mono 类并制作一个响应式(Reactive)休息 Controller
我们一直在为我们的应用程序使用 Springboot 1.X。 现在准备开始一些新的应用程序,想知道我们是应该使用 SpringBoot2.0 还是坚持使用 SpringBoot 1.X? 对一种方式
我希望记录应用程序正在加载 application-profile.propeties 或 application.yml。怎么做。在哪种方法中,我可以听取它并检测它是成功加载还是失败。 最佳答案 您
当我在 pom.xml 中添加简单的 spring-boot-starter-data-jpa 依赖项时,在 pom.xml 文件中出现错误。如果我删除该依赖项,则不会再有错误。我不确定为什么会发生这
我希望记录应用程序正在加载 application-profile.propeties 或 application.yml。怎么做。在哪种方法中,我可以听取它并检测它是成功加载还是失败。 最佳答案 您
我在网上看了很多关于 spring-boot-devtools 的文章和问题,但仍然无法弄清楚为什么它对我不起作用。每次运行我的应用程序时,我都会得到以下信息: 17:54:28.057 [main]
我正在尝试将现有的 Spring 应用程序移植到 Spring Boot。我不使用 spring-boot-starter-data-solr 启动器,但是我的类路径上有 apache solrj (
(这主要是一个历史问题。Pivotal 建议所有论坛讨论都在 StackOverflow 上进行,这就是我在这里问它的原因。) Spring Boot 项目用来证明将应用程序的类和依赖项从可执行 ja
我是一名优秀的程序员,十分优秀!