分布式处理方案

分布式处理方案

在这里插入图片描述
在这里插入图片描述

一、分布式锁介绍

  • 由于传统的锁是基于Tomcat服务器内部的,搭建了集群之后,导致锁失效
  • 使用分布式锁来处理
    在这里插入图片描述

二、分布式锁解决方案

2.1 搭建环境

1、创建SpringBoot工程
2、编写抢购业务

@RestController
public class SecondKillController {
    //1、准备商品的库存
    public static Map<String,Integer> itemStock=new HashMap<>();


    //2、准备商品的订单
    public static Map<String,Integer> itemOrder=new HashMap<>();

    static {
        itemStock.put("牙刷",10000);
        itemOrder.put("牙刷",0);
    }

    @GetMapping("/kill")
    public String kill(String item) throws InterruptedException {
        //1、减库存
        Integer stock=itemStock.get(item);
        if (stock<=0){
            return "商品库存不足!!!";
        }
        Thread.sleep(100);
        itemStock.put("牙刷",stock-1);
        //2、创建订单
        Thread.sleep(100);
        itemOrder.put(item,itemOrder.get(item)+1);

        //3、返回信息
        return "抢购成功!!!"+item+":剩余库存数为 - "+itemStock.get(item)+",订单数为:"+itemOrder.get(item);
    }

}

3、下载ab压力测试
下载地址:https://www.apachehaus.com/cgi-bin/download.plx?dli=QZsZEaTtWQ41ERBJjSI5UWZNlVUNlVSZ0SsZERhdFO
使用方式:
cmd打开到bin目录,命令:

ab -n 请求数 -c 并发数 访问的路径

4、测试
在这里插入图片描述

2.2 Zookeeper实现分布式原理

在这里插入图片描述

2.3 Zookeeper实现分布式锁

1、导入依赖(需要排除几个依赖)

	<dependencies>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>log4j</artifactId>
                    <groupId>log4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

2、编写配置类

@Configuration
public class ZKConfig {

    @Bean
    public CuratorFramework cf(){
        RetryPolicy retrypolicy=new ExponentialBackoffRetry(3000,2);
        CuratorFramework curatorFramework=CuratorFrameworkFactory.builder()
                 .connectString("192.168.31.240:2181,192.168.31.240:2182,192.168.31.240:2183").
                         retryPolicy(retrypolicy).build();
        curatorFramework.start();
        return curatorFramework;
    }
}

3、在业务代码中添加分布式锁


@RestController
public class SecondKillController {
    @Autowired
    private CuratorFramework cf;

    //1、准备商品的库存
    public static Map<String,Integer> itemStock=new HashMap<>();


    //2、准备商品的订单
    public static Map<String,Integer> itemOrder=new HashMap<>();

    static {
        itemStock.put("牙刷",10000);
        itemOrder.put("牙刷",0);
    }

    @GetMapping("/kill")
    public String kill(String item) throws Exception {
        InterProcessMutex lock=new InterProcessMutex(cf,"/lock");

        //...加锁
        //lock.acquire();
        lock.acquire(1, TimeUnit.SECONDS);  //指定排队多久就放弃获取锁资源

//------------------------------业务代码------------------------------------------
        //释放锁
        lock.release();

        //3、返回信息
        return "抢购成功!!!"+item+":剩余库存数为 - "+itemStock.get(item)+",订单数为:"+itemOrder.get(item);
    }

}

2.4 Redis实现分布式锁的原理

在这里插入图片描述

2.5 Redis实现分布式锁

1、导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

指定redis连接信息

spring:
  redis:
    host: 192.168.31.240
    port: 6379

2、编写工具类

@Component
public class RedisLockUtil {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/redis/kill")
    public boolean lcok(String key,String value,int second){
        return redisTemplate.opsForValue().setIfAbsent(key,value,second, TimeUnit.SECONDS);
    }

    @GetMapping("/zk/kill")
    public void  unlock(String key){
        redisTemplate.delete(key);
    }

}

3、修改业务逻辑代码

    @GetMapping("/rediskill")
    public String rediskill(String item) throws Exception {

        //...加锁
        if (lock.lcok(item,System.currentTimeMillis()+"",1)){
            //1、减库存
            Integer stock=itemStock.get(item);
            if (stock<=0){
                return "商品库存不足!!!";
            }
            Thread.sleep(100);
            itemStock.put("牙刷",stock-1);
            //2、创建订单
            Thread.sleep(100);
            itemOrder.put(item,itemOrder.get(item)+1);

            //释放锁
            lock.unlock(item);

            //3、返回信息
            return "抢购成功!!!"+item+":剩余库存数为 - "+itemStock.get(item)+",订单数为:"+itemOrder.get(item);
        }else {
            return "没有抢到商品";
        }
    }

4、测试
ab压力测试

三、分布式任务介绍

在这里插入图片描述

四、分布式任务解决方案

4.1 Elastic-Job介绍

官网:http://shardingsphere.apache.org/elasticjob/
由当当网基于Quartz+Zookeeper的二次开发产品
1、基于Zookeeper分布式锁,保证只有一个服务去执行定时任务
2、基于Zookeeper实现了注册中心,自动帮助我们去调度指定的服务执行定时任务。
3、基于Zookeeper实现了注册中心,基于心跳的方式,自动去检测服务的健康情况。

4.2 Elastic-Job实现分布式任务

1、创建SpringBoot工程
2、导入依赖

        <dependency>
            <groupId>com.dangdang</groupId>
            <artifactId>elastic-job-lite-spring</artifactId>
            <version>2.1.5</version>
        </dependency>

3、配置Zookeeper信息

@Configuration
public class ElasticJobConfig {

    //注册中心
    @Bean
    public CoordinatorRegistryCenter center(){
        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(
                new ZookeeperConfiguration("192.168.0.142:2181,192.168.0.142:2182,192.168.0.142:2183", "elastic-job-demo"));
        regCenter.init();
        return regCenter;
    }
}

4、创建指定的定时任务

@Component
public class MyElasticJob implements SimpleJob {

    @Override
    public void execute(ShardingContext context) {
        switch (context.getShardingItem()) {
            case 0:
                System.out.println("执行0任务");
                break;
            case 1:
                System.out.println("执行1任务");
                break;
            case 2:
                System.out.println("执行2任务");
                break;
            // case n: ...
        }
    }
}

5、配置执行的周期,并且开始调度任务


@SpringBootApplication
public class JobApplication {

    public static void main(String[] args) {
        SpringApplication.run(JobApplication.class, args);
    }


    //指定任务调度信息
    @Bean
    public SpringJobScheduler scheduler(MyElasticJob job, CoordinatorRegistryCenter center){
        // 定义作业核心配置
        JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.
                newBuilder("demoSimpleJob", "0/10 * * * * ?", 3).shardingItemParameters("0=A,1=B,2=C").build();
        // 定义SIMPLE类型配置
        SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, MyElasticJob.class.getCanonicalName());
        // 定义Lite作业根配置
        LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();

        //定义SpringJobScheduler
        SpringJobScheduler scheduler=new SpringJobScheduler(job,center,simpleJobRootConfig);
        scheduler.init();
        return scheduler;
    }
}

6、测试

五、分布式事务介绍

5.1 引言

在这里插入图片描述

5.2 Base理论

  • CAP理论,C:一致性,A:可用性,P:分区容错性,三者取其二。

    • Eureka:AP ,保证可用性,舍弃了一致性
    • Zookeeper:CP,每一个节点必须能够找到Master才能对外提供服务,舍弃了可用性。
  • Base理论,BA:基本可用,S:中间状态,E:最终一致性

    • 基于CAP理论演化而来的,是对CAP定理中一致性和可用性的一个权衡结果。
    • 核心思想:我们无法做到强一致性,但是每一个应用都可以根据自身的业务特点,采用一些适当的方式来权衡,最终达到一致性。
    • BA:分布式系统中因为一个原因,导致出现了一些问题,允许损失掉部分服务的可用性,保证我核心功能的高可用。
    • S:允许系统之间存在一个中间状态,并不会影响正常的去使用整个系统,允许数据的同步存在延迟
    • E:系统中所有的数据副本经过一定时间后,最终能够达到一致的状态,不需要保证系统数据强一致性。

六、分布式事务解决方案

  • 软性事务(Base理论),刚性事务(ACID)。

6.1 PC两端提交

  • 两端提交分为两个阶段

    • 第一阶段是准备阶段,参与者需要开启事务,执行SQL,保证数据库中已经存在应该的数据。参与者回向TransactionManager准备OK。
    • 第二阶段当TransactionManager收到了所有的参与者的通知之后,向所有的参与者发送Commit请求。
  • 问题1:执行的性能是很低的,一般是传统事务的10倍以上。

  • 问题2:TransactionManager是没有超时时间的。

  • 问题3:TransactionManager存在单点故障的问题。
    在这里插入图片描述

6.2 3PC三端提交

  • 1、三段提交在二段提交的基础上,引入了超时时间机制,并且在二段提交的基础上,又多了一个步骤,在提交事务之前,在询问一下,数据库的日志信息,是否已经完善。
    在这里插入图片描述

6.3 TCC机制

  • TCC(Try,Confirm,Cancel),和你的业务代码切合在一起。
    • Try:尝试去预执行具体业务代码。下单…
    • try成功了,Confirm:再次执行Confirm的代码
    • try失败了,Cancel:再次执行Cancel的代码。
      在这里插入图片描述

6.4 MQ分布式事务

  • RabbitMQ在发送消息时,confirm机制,可以保证消息发送到MQ服务中,消费者有手动ack机制,保证消费到MQ中的消息。
    在这里插入图片描述

6.5 LCN实现分布式事务

  • 基于三段提交和TCC实现的
    1、创建一个协调者工程,创建两个服务
    2、协调者:添加依赖,编写配置文件,添加注解
  • 依赖
        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tm</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
@SpringBootApplication
@EnableTransactionManagerServer
public class TxManagerApplication {

    public static void main(String[] args) {
        SpringApplication.run(TxManagerApplication.class, args);
    }

}
  • application.yml
server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///lcn?serverTimezone=UTC
    username: root
    password: 123456
  redis:
    host: 192.168.31.240
    port: 6379
# 协调的端口号
tx-lcn:
  manager:
    port: 8070
  • 启动类添加
@EnableTransactionManagerServer

  • 创建tx-lcn表
DROP TABLE IF EXISTS `t_tx_exception`;
CREATE TABLE `t_tx_exception`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `group_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `mod_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `transaction_state` tinyint(4) NULL DEFAULT NULL,
  `registrar` tinyint(4) NULL DEFAULT NULL COMMENT '-1 未知 0 Manager 通知事务失败, 1 client询问事务状态失败2 事务发起方关闭事务组失败',
  `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 待处理 1已处理',
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 967 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

3、服务:添加依赖,编写配置文件,添加注解

  • 依赖
 <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-txmsg-netty</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>

  • application.yml
server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///lcn?serverTimezone=UTC
    username: root
    password: 123456
# 协调的端口号
tx-lcn:
  manager:
    port: 8070
  • 启动类添加注解
@EnableDistributedTransaction

  • 开启事务,在server层添加
@Service
public class ServiceA {
    
    @Autowired
    private ValueDao valueDao; //本地db操作
    
    @Autowired
    private ServiceB serviceB;//远程B模块业务
    
    @LcnTransaction //分布式事务注解
    @Transactional //本地事务注解
    public String execute(String value) throws BusinessException {
        // step1. call remote service B
        String result = serviceB.rpc(value);  // (1)
        // step2. local store operate. DTX commit if save success, rollback if not.
        valueDao.save(value);  // (2)
        valueDao.saveBackup(value);  // (3)
        return result + " > " + "ok-A";
    }
}

4、测试
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值