前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud微服务实战系列(十三)分布式锁之Redis实现(redisson)

SpringCloud微服务实战系列(十三)分布式锁之Redis实现(redisson)

作者头像
品茗IT
发布2020-05-28 16:10:18
2.3K0
发布2020-05-28 16:10:18
举报
文章被收录于专栏:品茗IT

SpringCloud微服务实战系列(十三)分布式锁之Redis实现(redisson)

一、概述

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

数据库的悲观锁和乐观锁也能保证不同主机共享数据的一致性。但是却存在以下问题:

  • 悲观锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。
  • 一旦悲观锁解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁
  • 乐观锁适合读多写少的场景,如果在分布式场景下使用乐观锁,就会导致总是更新失败,效率极低。

本文使用Redis分布式锁的开源项目redisson做分布式锁的简单实现。

redisson官网:分布式锁和同步器

代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的LockRedis、LockSupport和LockTest组件中查看,并下载。LockSupport和LockTest是配合LockRedis的测试项目。

**如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以<a

href="https://jq.qq.com/?_wv=1027&k=52sgH1J"

target="_blank">

加入我们的java学习圈,点击即可加入

</a>

,共同学习,节约学习时间,减少很多在学习中遇到的难题。**

二、准备工作

首先是必然要安装redis的。其次,我们要了解redisson锁的种类,为了配合锁的使用,使用了LockSupport和LockTest两个项目分别做商品服务和客户端测试,多个项目使用Consul做服务注册与发现。这里会简单介绍下LockSupport、LockRedis和LockTest三个项目是如何配合使用分布式锁的。

2.1 redisson锁的种类

redisson为我们提供了很多种锁,如:

可重入锁(Reentrant Lock) :基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。

公平锁(Fair Lock) :基于Redis的Redisson分布式可重入公平锁也是实现了java.util.concurrent.locks.Lock接口的一种RLock对象。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。它保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。

联锁(MultiLock) :基于Redis的Redisson分布式联锁RedissonMultiLock对象可以将多个RLock对象关联为一个联锁,每个RLock对象实例可以来自于不同的Redisson实例。

红锁(RedLock) :基于Redis的Redisson红锁RedissonRedLock对象实现了Redlock介绍的加锁算法。该对象也可以用来将多个RLock对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例。

读写锁(ReadWriteLock) :基于Redis的Redisson分布式可重入读写锁RReadWriteLock Java对象实现了java.util.concurrent.locks.ReadWriteLock接口。其中读锁和写锁都继承了RLock接口。

信号量(Semaphore) :基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。

可过期性信号量(PermitExpirableSemaphore) :基于Redis的Redisson可过期性信号量(PermitExpirableSemaphore)是在RSemaphore对象的基础上,为每个信号增加了一个过期时间。每个信号可以通过独立的ID来辨识,释放时只能通过提交这个ID才能释放。它提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。

闭锁(CountDownLatch) :基于Redisson的Redisson分布式闭锁(CountDownLatch)Java对象RCountDownLatch采用了与java.util.concurrent.CountDownLatch相似的接口和用法。

锁的种类虽多,但是使用方法都是类似的,本文就选择公平锁来测试使用。

2.2 LockSupport模拟商品服务

LockSupport代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的LockSupport组件中下载,这里就只说LockSupport的功能。

LockSupport只是个简单的SpringBoot项目,使用Spring Data Jpa做数据库操作,开放以下接口做服务:

  • goods/take 接口,做商品信息查询;
  • goods/page 接口,做商品分页查询;
  • goods/consume 接口,做商品消费。
2.3 LockRedis是分布式锁的使用

LockRedis代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的LockRedis组件中下载。

第三章节将详细介绍LockRedis项目。

2.4 LockTest模拟客户端请求

LockTest代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的LockTest组件中下载,这里就只说LockSupport的功能。

LockTest只是个简单的SpringBoot项目,使用Feign请求LockRedis来测试分布式锁的使用。

三、分布式锁的使用

下面详细介绍LockRedis是如何使用redisson做分布式锁的。

3.1 引入依赖

需要引入数据库相关jar、jpa、spring-boot-starter-data-redis、redisson-spring-boot-starter;

因为使用了consul做服务注册发现,需要引入spring-cloud-starter-consul-discovery和spring-cloud-starter-openfeign。

依赖如下:

代码语言:javascript
复制
<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>cn.pomit</groupId>
		<artifactId>springcloudwork</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>LockRedis</artifactId>
	<name>LockRedis</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.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.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<!-- redis -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<!-- redisson -->
		<dependency>
			<groupId>org.redisson</groupId>
			<artifactId>redisson-spring-boot-starter</artifactId>
			<version>3.11.0</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.34</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
		</dependency>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
	</dependencies>
</project>

父模块pom文件可以在https://www.pomit.cn/spring/SpringCloudWork/pom.xml获取。

3.2 配置文件

这里使用yaml文件写配置,配置文件application.yml:

application.yml:

代码语言:javascript
复制
server:
   port: 8018
   useLock: true
spring:
   application:
      name: lockService
   cloud:
      consul:
         host: 127.0.0.1
         port: 8500
         discovery:
            prefer-ip-address: true
            healthCheckPath: /consul/health
   redis:
      database: 0
      port: 6379
      host: 192.168.99.100
      lettuce:
         pool:
            max-idle: 8
            min-idle: 5
            max-active: 10
            max-wait: 1000
      timeout: 1000
   datasource:
      type: org.apache.commons.dbcp2.BasicDataSource
      dbcp2:
         max-wait-millis: 60000
         min-idle: 20
         initial-size: 2
         connection-properties: characterEncoding=utf8
         validation-query: SELECT 1
         test-while-idle: true
         test-on-borrow: true
         test-on-return: false
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
      username: cff
      password: 123456
logging:
   level:
      root: INFO

这里,应用名称是lockService,在8018端口监听。

  • spring.cloud.consul开头的配置时consul服务注册发现的配置。前面章节已经有说明。
  • spring.redis.*是Spring Data Redis相关配置,SpringBoot入门建站全系列(十四)集成Redis缓存文章已说明;
  • spring.datasource.*是数据库配置,前面章节已说明。
  • logging.*是开启日志
  • server.useLock是自定义配置。用于控制是否开启分布式锁。
3.3 Feign请求商品服务

这里使用@FeignClient来请求lockSupport项目,获取商品信息或者消费商品。

GoodsInfoService :

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.inter;

import java.util.List;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import cn.pomit.springbootwork.lock.redis.domain.TGoodInfo;

@FeignClient("lockSupport")
public interface GoodsInfoService {
	@RequestMapping(method = RequestMethod.GET, value = "/goods/take", consumes = "application/json")
	public TGoodInfo getGoodsInfo(@RequestParam("goodId") Integer goodId);

	@RequestMapping(method = RequestMethod.GET, value = "/goods/page", consumes = "application/json")
	public List<TGoodInfo> getGoodsList(@RequestParam("page") Integer page, @RequestParam("size") Integer size);

	@RequestMapping(method = RequestMethod.GET, value = "/goods/consume", consumes = "application/json")
	public Integer consume(@RequestParam("goodId") Integer goodId, @RequestParam("num") Integer num, @RequestParam("serverId") Integer serverId);
}
3.4 消费逻辑

消费的业务逻辑只是简单的处理商品,并调用GoodsInfoService 进行商品信息服务请求。

UserConsumeService:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.service;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import cn.pomit.springbootwork.lock.redis.dao.TUserGoodDao;
import cn.pomit.springbootwork.lock.redis.domain.TGoodInfo;
import cn.pomit.springbootwork.lock.redis.domain.TUserGood;
import cn.pomit.springbootwork.lock.redis.dto.ResultModel;
import cn.pomit.springbootwork.lock.redis.inter.ConsumeService;
import cn.pomit.springbootwork.lock.redis.inter.GoodsInfoService;

@Service("UserConsumeService")
public class UserConsumeService implements ConsumeService {
	protected Logger log = LoggerFactory.getLogger(this.getClass());
	@Autowired
	GoodsInfoService goodsInfoService;
	@Autowired
	TUserGoodDao tUserGoodDao;

	@Value("${server.port}")
	private Integer serverId;

	public ResultModel goodList(Integer page, Integer size) {
		List<TGoodInfo> pageList = goodsInfoService.getGoodsList(page, size);
		return ResultModel.ok(pageList);
	}

	public ResultModel goodDetail(Integer goodId) {
		return ResultModel.ok(goodsInfoService.getGoodsInfo(goodId));
	}

	public ResultModel consume(Integer goodId, Integer num, String userName) {
		log.info("开始消费:userName:{};goodId:{},num:{}", userName, goodId, num);

		TGoodInfo tGoodInfo = goodsInfoService.getGoodsInfo(goodId);

		log.info("消费前:goodId:{}剩余:{}", goodId, tGoodInfo.getGoodNum());

		Integer ret = goodsInfoService.consume(goodId, num, serverId);

		log.info("消费结果:ret:{};", ret);
		if (ret > 0) {
			log.info("保存用户消费信息");
			TUserGood tUserGood = new TUserGood();
			tUserGood.setConsumeNum(num);
			tUserGood.setGoodId(goodId);
			tUserGood.setUserName(userName);
			tUserGoodDao.save(tUserGood);
			return ResultModel.ok();
		}
		return ResultModel.error("消费失败!");
	}

}

同时,这个业务逻辑实现了ConsumeService接口:

ConsumeService:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.inter;

import cn.pomit.springbootwork.lock.redis.dto.ResultModel;

public interface ConsumeService {
	public ResultModel goodList(Integer page, Integer size);

	public ResultModel goodDetail(Integer goodId);

	public ResultModel consume(Integer goodId, Integer num, String userName);
}

实现这个接口,是为了使用代理模式。

3.5 分布式锁逻辑

DistributedLocker类实现基于redis的分布式锁。

  • 自动注入RedissonClient,并使用RedissonClient来获取锁,这里获取一个公平锁RLock lock = redissonClient.getFairLock;
  • lock.tryLock成功获取到锁之后,调用LockWorker的invoke方法,执行传入的LockWorker对象。
  • 执行完成后,lock.unlock()释放锁。
  • 可以用过useLock属性来控制是否使用分布式锁。

DistributedLocker :

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.lock;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import cn.pomit.springbootwork.lock.redis.dto.ResultModel;
import cn.pomit.springbootwork.lock.redis.inter.LockWorker;

public class DistributedLocker {
	protected Logger log = LoggerFactory.getLogger(this.getClass());
	public final static String LOCKER_PREFIX = "lock:";
	public final static String LOCKER_GOODS_CONSUME = "GOODS_CONSUME";

	public final static Long LOCKER_WAITE_TIME = 10l;

	public final static Long LOCKER_LOCK_TIME = 100l;

	@Value("${server.port}")
	private Integer serverId;

	@Value("${server.useLock}")
	private boolean useLock = true;

	/**
	 * The Redisson client.
	 */
	@Autowired
	protected RedissonClient redissonClient;

	public ResultModel tryLock(LockWorker lockWorker) {
		try {
			if (useLock) {
				log.info("当前server 节点为:{}", serverId);
				log.info("开始获取lock key:{}", LOCKER_PREFIX + LOCKER_GOODS_CONSUME);
				RLock lock = redissonClient.getFairLock(LOCKER_PREFIX + LOCKER_GOODS_CONSUME);
				log.info("创建lock key:{},尝试lock", LOCKER_PREFIX + LOCKER_GOODS_CONSUME);
				// (公平锁)最多等待10秒,锁定后经过lockTime秒后自动解锁
				boolean success = lock.tryLock(LOCKER_WAITE_TIME, LOCKER_LOCK_TIME, TimeUnit.SECONDS);
				if (success) {
					try {
						log.info("成功到获取lock key:{}", LOCKER_PREFIX + LOCKER_GOODS_CONSUME);
						return lockWorker.invoke();
					} finally {
						log.info("释放lock key:{}", LOCKER_PREFIX + LOCKER_GOODS_CONSUME);
						lock.unlock();
					}
				}
				log.info("获取lock key:{}失败", LOCKER_PREFIX + LOCKER_GOODS_CONSUME);
				return ResultModel.error("获取分布式锁失败!");
			} else {
				log.info("当前server 节点为:{}", serverId);
				log.info("当前server 没有使用分布式锁:{}");
				return lockWorker.invoke();
			}
		} catch (Exception e) {
			log.error("获取lock key异常", e);
			return ResultModel.error("获取分布式锁过程异常!");
		}
	}

	public Integer getServerId() {
		return serverId;
	}

	public void setServerId(Integer serverId) {
		this.serverId = serverId;
	}
}
3.6 代理消费业务

为了避免对代码侵入性太强,我这里使用代理模式,使用LockWorker来操作消费业务。这样,如果想去掉分布式锁的代码,只需注掉代理即可。

UserConsumeServiceProxy:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.pomit.springbootwork.lock.redis.dto.ResultModel;
import cn.pomit.springbootwork.lock.redis.inter.ConsumeService;
import cn.pomit.springbootwork.lock.redis.inter.LockWorker;
import cn.pomit.springbootwork.lock.redis.lock.DistributedLocker;

@Service("consumeService")
public class UserConsumeServiceProxy extends DistributedLocker implements ConsumeService {
	@Autowired
	UserConsumeService userConsumeService;

	public ResultModel goodList(Integer page, Integer size) {
		return userConsumeService.goodList(page, size);
	}

	public ResultModel goodDetail(Integer goodId) {
		return userConsumeService.goodDetail(goodId);
	}

	public ResultModel consume(Integer goodId, Integer num, String userName) {
		LockWorker lockWorker = new LockWorker() {
			@Override
			public ResultModel invoke() throws Exception {
				log.info("开始远程消费:userName:{};goodId:{},num:{}", userName, goodId, num);
				return userConsumeService.consume(goodId, num, userName);
			}
		};

		return tryLock(lockWorker);
	}

}

LockWorker 接口:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.inter;

import cn.pomit.springbootwork.lock.redis.dto.ResultModel;

public interface LockWorker {
	
	ResultModel invoke() throws Exception;
}

四、测试web

开放web接口,给模拟的客户端LockTest测试使用。

LockRedisRest:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.web;

import java.security.Principal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.springbootwork.lock.redis.dto.ResultModel;
import cn.pomit.springbootwork.lock.redis.inter.ConsumeService;

@RestController
@RequestMapping("/lock")
public class LockRedisRest {
	private Logger log = LoggerFactory.getLogger(this.getClass());
	@Autowired
	ConsumeService consumeService;

	@RequestMapping(value = "/goodList")
	public ResultModel goodList(@RequestParam(value = "page", required = false) Integer page,
			@RequestParam(value = "size", required = false) Integer size) {
		return consumeService.goodList(page, size);
	}

	@RequestMapping(value = "/goodDetail")
	public ResultModel goodDetail(@RequestParam("goodId") Integer goodId) {
		return consumeService.goodDetail(goodId);
	}

	@RequestMapping(value = "/consume")
	public ResultModel consume(@RequestParam("goodId") Integer goodId, @RequestParam("num") Integer num,
			Principal principal) {
		String userName = "test";
		if (principal != null && !StringUtils.isEmpty(principal.getName())) {
			userName = principal.getName();
		}
		log.info("收到消费请求:userName:{};goodId:{}", userName, goodId);
		return consumeService.consume(goodId, num, userName);
	}
}

五、启动类

LockRedisApplication:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class LockRedisApplication {
	public static void main(String[] args) {
		SpringApplication.run(LockRedisApplication.class, args);
	}

	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

六、数据库操作

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import cn.pomit.springbootwork.lock.redis.domain.TUserGood;

public interface TUserGoodDao extends JpaRepository<TUserGood, Integer> {

}

七、Consul的健康检测

这个是使用consul做注册中心才需要的。

HealthWeb:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/consul")
public class HealthWeb {

	@RequestMapping(value = "health", method = { RequestMethod.GET })
	public String health() {
		return "check health";
	}
	
}

八、使用到的实体

TUserGood:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.domain;

import javax.persistence.Table;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Column;

@Entity
@Table(name = "t_user_good")
public class TUserGood {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	@Column(name = "good_id")
	private int goodId;
	@Column(name = "consume_num")
	private int consumeNum;
	@Column(name = "user_name")
	private String userName;

	public void setId(int id) {
		this.id = id;
	}

	public int getId() {
		return id;
	}

	public void setGoodId(int goodId) {
		this.goodId = goodId;
	}

	public int getGoodId() {
		return goodId;
	}

	public void setConsumeNum(int consumeNum) {
		this.consumeNum = consumeNum;
	}

	public int getConsumeNum() {
		return consumeNum;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getUserName() {
		return userName;
	}

}

TGoodInfo:

代码语言:javascript
复制
package cn.pomit.springbootwork.lock.redis.domain;

import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;

public class TGoodInfo {
	private Integer id;
	private String goodName;
	private String goodDesc;
	@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
	private Date createTime;
	private int goodNum;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public void setGoodName(String goodName) {
		this.goodName = goodName;
	}

	public String getGoodName() {
		return goodName;
	}

	public void setGoodDesc(String goodDesc) {
		this.goodDesc = goodDesc;
	}

	public String getGoodDesc() {
		return goodDesc;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	public Date getCreateTime() {
		return createTime;
	}

	public int getGoodNum() {
		return goodNum;
	}

	public void setGoodNum(int goodNum) {
		this.goodNum = goodNum;
	}

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/09/25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringCloud微服务实战系列(十三)分布式锁之Redis实现(redisson)
  • 一、概述
  • 二、准备工作
    • 2.1 redisson锁的种类
      • 2.2 LockSupport模拟商品服务
        • 2.3 LockRedis是分布式锁的使用
          • 2.4 LockTest模拟客户端请求
          • 三、分布式锁的使用
            • 3.1 引入依赖
              • 3.2 配置文件
                • 3.3 Feign请求商品服务
                  • 3.4 消费逻辑
                    • 3.5 分布式锁逻辑
                      • 3.6 代理消费业务
                      • 四、测试web
                      • 五、启动类
                      • 六、数据库操作
                      • 七、Consul的健康检测
                      • 八、使用到的实体
                      相关产品与服务
                      云数据库 Redis®
                      腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档