分布式锁、分布式定时任务、分布式事务


在这里插入图片描述

  在分布式环境下,传统的一些技术会失败,比如传统的 synchronized 或者 lock 锁,以及创建数据库的事务,无法保证ACID,还有定时任务也可能会出现重复执行的问题。

  分布式锁。Zookeeper 实现分布式锁。

  创建 spring boot 工程。


// pom.xml

 	<dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>log4j</artifactId>
                    <groupId>log4j</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>


// ZkUtils.java 

@Configuration
public class ZkUtils {

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


// SecondKillController.java

@RestController
public class SecondKillController {

    @Autowired
    private CuratorFramework curatorFramework;

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

    // 商品清单
    public static Map<String, Integer> itemOrder = new HashMap<>();

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

    @RequestMapping("/zkKill")
    public String zkKill(String item) throws Exception {

        //InterProcessMutex基于Zookeeper实现了分布式互斥锁
        InterProcessMutex lock = new InterProcessMutex(curatorFramework,"/lock");

        lock.acquire();

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

        Integer stock = itemStock.get(item);
        if (stock <= 0) {
            return "商品库存不足!!!!";
        }
        itemStock.put(item, stock - 1);

        Thread.sleep(100);

        Integer order = itemOrder.get(item);
        itemOrder.put(item, order + 1);

        lock.release();

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

  分布式定时任务。
  Elastic-Job 实现分布式任务。
  由当当网基于Quartz + Zookeeper的二次开放产品。
  基于Zookeeper分布式锁,保证只有一个服务去执行定时任务。
  基于Zookeeper实现了注册中心,自动帮助我们去调度指定的服务执行定时任务。
  基于Zookeeper实现了注册中心,基于心跳的方式,自动去检测服务的健康情况。

  配置 VM options 运行多个服务,多个服务的任务不重复。


// pom.xml

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


// MyElasticJob

@Component
public class MyElasticJob implements SimpleJob {
    @Override
    public void execute(ShardingContext shardingContext) {
        switch (shardingContext.getShardingItem()) {
            case 0:
                System.out.println("执行任务1");
                break;
            case 1:
                System.out.println("执行任务2");
                break;
            case 2:
                System.out.println("执行任务3");
                break;
        }
    }
}

// ZkUtils.java

@Configuration
public class ZkUtils {

    @Bean
    public CoordinatorRegistryCenter center () {
        CoordinatorRegistryCenter registryCenter = new ZookeeperRegistryCenter(
                new ZookeeperConfiguration("10.36.144.157:2181,10.36.144.157:2182,10.36.144.157:2183", "elastic-job-demo")
        );
        registryCenter.init();
        return registryCenter;
    }

    //创建一个任务调度对象,并设置相关任务的调度信息(任务的执行时间)
    @Bean
    public SpringJobScheduler scheduler(MyElasticJob job, CoordinatorRegistryCenter registryCenter){
        // 0/5 * * * * 每五秒执行一次,3表示作业的分片
        JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("demoSimpleJob",
                "0/5 * * * * ?", 3).build();

        SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig,
                MyElasticJob.class.getCanonicalName());

        LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
        //在项目启动时,就会自动开始执行任务调度
        SpringJobScheduler jobScheduler = new SpringJobScheduler(job,registryCenter,simpleJobRootConfig);
        jobScheduler.init();
        return jobScheduler;
    }
}

  LCN 实现分布式事务。基于三段提交和TCC实现的。

  创建 spring boot 一个协调者工程。


// manager

// pom.xml
		<dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tm</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>


// application.xml 
// 注意 application.properties 文件需要保留,不然数据库报错

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///dbTest1?serverTimezone=UTC
    username: root
    password: 123
  redis:
    host: 10.36.144.157
    port: 6379
#协调端口
tx-lcn:
  manager:
    port: 8070

// DemoApplication.java

@SpringBootApplication
@EnableTransactionManagerServer
public class DemoApplication {

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

}


  创建一个 product 服务。


// product

// pom.xml

	<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

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

// application.yml

server:
  port: 8081

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///dbTest1?serverTimezone=UTC
    username: root
    password: 123

# 注册到管理端
tx-lcn:
  client:
    manager-address: localhost:8070


// ProductMapper.java

public interface ProductMapper {

    @Update("update air set pm10=pm10-1 where id=1")
    void updateStock();

}

// ProductService.java

public interface ProductService {

    void updateStock();

}


// ProductServiceImpl.java

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;

    @Override
    @Transactional
    @LcnTransaction
    public void updateStock() {

//        int i = 1 / 0;

        productMapper.updateStock();
    }
}

// DemoApplication.java

@SpringBootApplication
@EnableDistributedTransaction
@MapperScan("com.example.demo.mapper")
public class DemoApplication {

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

}

// ProductController 
// http://localhost:8081/updateStock

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @RequestMapping("/updateStock")
    public String updateStock() {
        productService.updateStock();
        return "product success";
    }

}


  创建一个 order 服务。


// order

// pom.xml

	<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

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

// application.yml

server:
  port: 8082

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///dbTest1?serverTimezone=UTC
    username: root
    password: 123

# 注册到管理端
tx-lcn:
  client:
    manager-address: localhost:8070

// OrderMapper.java

public interface OrderMapper {

    @Insert("insert into role values(null,'kk','kkk',0)")
    void add();

}

// OrderService.java

public interface OrderService {

    void add();

}

// OrderServiceImpl.java

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Override
    @Transactional
    @LcnTransaction
    public void add() {

        orderMapper.add();

    }
}

// DemoApplication.java

@SpringBootApplication
@EnableDistributedTransaction
@MapperScan("com.example.demo.mapper")
public class DemoApplication {

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

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}


// OrderController.java

@RestController
public class OrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/add")
    public String add() {

        orderService.add();

        String res = restTemplate.getForObject("http://localhost:8081/updateStock", String.class);

        if (res != null) {
            return res;
        }

        return "order success";
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值