分布式并发安全-引入

分布式

分布式/集群单体 不同主要在于并发问题

分布式并发问题

分布式并发问题主要是指在分布式系统中,由于多个节点之间的并发操作,可能会导致数据不一致、状态不一致等问题。

example

后端设置

先把application再运行一个

一个运行在8081端口,另一个运行在8082端口

前端设置

nginx.conf中设置负载均衡

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

worker_processes 1;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/json;

sendfile on;

keepalive_timeout 65;

server {
listen 8080;
server_name localhost;
# 指定前端项目所在的位置
location / {
root html/hmdp;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}


location /api {
default_type application/json;
#internal;
keepalive_timeout 30s;
keepalive_requests 1000;
#支持keep-alive
proxy_http_version 1.1;
rewrite /api(/.*) $1 break;
proxy_pass_request_headers on;
#more_clear_input_headers Accept-Encoding;
proxy_next_upstream error timeout;
# proxy_pass http://127.0.0.1:8081;
proxy_pass http://backend;
}
}

# 反向代理到后端服务 负载均衡
upstream backend {
server 127.0.0.1:8081 max_fails=5 fail_timeout=10s weight=1;
server 127.0.0.1:8082 max_fails=5 fail_timeout=10s weight=1;
}
}

nginx的反向代理和负载均衡默认使用轮询的方式

测试

  1. 启动两个后端服务

  2. 启动前端服务

  3. 打开浏览器,多次访问http://localhost:8080/api/voucher/list/1

  4. 查看两个后端服务的日志

可以看到请求是交替到两个后端服务的

并发问题

使用两个相同用户访问http://localhost:8080/api/voucher-order/seckill/7进行秒杀下单时,看到数据库减少了两条数据
但是实际上只应该减少一条数据
这就是并发问题
在分布式系统中,由于多个节点之间的并发操作,可能会导致数据不一致、状态不一致等问题
在这个例子中,两个请求同时访问了/api/voucher-order/seckill/7,导致两个请求都成功下单了

原理

在单体应用中,使用的synchronized关键字来保证线程安全,注意此时单独的jvm,所以锁监视器只有一个,可以监控到哪个线程获取到锁,哪个线程没有获取到锁,保证线程安全

alt text

而在分布式系统中,由于存在多个jvm,所以锁监视器是分开的,在对应的jvm中能够监控到哪个线程获取到锁,哪个线程没有获取到锁,但是在不同的jvm中是无法监控到其他jvm中的线程的,所以在分布式系统中,使用synchronized关键字是无法保证线程安全的

alt text

解决方案

使用唯一锁监视器来监控全部的jvm中的线程
在分布式系统中,使用redis的分布式锁来保证线程安全…