SpringCloud Alibaba 之 Config配置中心,Redis分布式锁详解

news2024/11/23 3:31:32

目录

1.服务配置中心

1.1 服务配置中心介绍

 1.2 Nacos Config 实践

1.2.1 Nacos config 入门案例

 1.2.2  Nacos 配置动态刷新

1.2.3 配置共享

1.2.4 nacos 几个概念

2.分布式锁

2.1 分布式锁介绍

 2.2 Redisson 

2.2.1 Redisson 实践

 2.2.2 Redisson 原理


1.服务配置中心

1.1 服务配置中心介绍

首先我们来看一下,微服务架构下关于配置文件的一些问题:
1.配置文件相对分散。在一个微服务架构下,配置文件会随着微服务的增多变的越来越多,而且分散在各个微服务中,不好统─配置和管理。
⒉.配置文件无法区分环境。微服务项目可能会有多个环境,例如︰测试环境、预发布环境、生产环境。每一个环境所使用的配置理论上都是不同的,一旦需要修改,就需要我们去各个微服务下手动维护,这比较困难。
3.配置文件无法实时更新。我们修改了配置文件之后,必须重新启动微服务才能使配置生效,这对一个正在运行的项目来说是非常不友好的。


基于上面这些问题,我们就需要配置中心的加入来解决这些问题。
配置中心的思路是:
1.首先把项目中各种配置全部都放到一个集中的地方进行统—管理,并提供—套标准的接口。
2.当各个服务需要获取配置的时候,就来配置中心的接口拉取自己的配置。
3..当配置中心中的各种参数有更新的时候,也能通知到各个服务实时的过来同步最新的信息,使之动态更新

当加入了服务配置中心之后,我们的系统架构图会变成下面这样:

 1.2 Nacos Config 实践

使用nacos作为配置中心,其实就是将nacos当做一个服务端,将各个微服务看成是客户端,我们将各个微服务的配置文件统一存放在nacos上,然后各个微服务从nacos上拉取配置即可。

1.2.1 Nacos config 入门案例

导入依赖

       <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

在微服务中添加nacos config的配置,不能使用原来的application.yml作为配置文件,而是新建一个bootstrap.yml作为配置文件。

配置文件优先级从高到低为:

bootstrap.properties>bootstrap.yml>application.properties>application.yml

这里举例为订单微服务,首先新建个bootstrap.yml文件,然后配置如下:

spring:
  application:
    name: provider
  profiles:
    active: dev #环境标识
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml #配置文件格式
      discovery:
        cluster-name: BJ
    sentinel:
      transport:
        dashboard: localhost:8080

然后在nacos配置文件中配置Data ID为bootstrap中配置订单微服务名+环境标识+配置文件格式。如下图;

 1.2.2  Nacos 配置动态刷新

实现在配置中心修改配置文件内容后,程序内部引用可以自动刷新,我们可以在自己创建的DataId配置文件中,更改项:

config: 
 
appName: product

硬编码方式

 @GetMapping("/test")
    public String test(){
        String property = configurableApplicationContext.getEnvironment().getProperty("config.appName");
        return property;
    }

注解方式

@RestController
@RefreshScope  /* 只需要在需要动态读取配置的类上添加此注解就可以 */

public class UserController {

    @Value("${config.appName}")
    private String appName;

    @GetMapping("/test")
    public String test(){
        return appName;
    }

}

1.2.3 配置共享

当配置越来越多的时候,我们就发现有很多配置是重复的,这时候就考虑可不可以将公共配置文件提取出来,然后实现共享。共享存在两种场景:同一微服务,不同场景(namespace)下共享;不同微服务之间共享。

 同一微服务,不同场景下共享配置

比如上面的订单微服务,开发环境的配置文件为provider-dev.yaml,测试环境的配置文件为provider-test.yaml,同一微服务在不同场景下共享可以配置provider.yaml文件。

 不同微服务之间共享共享配置

在nacos中新建all-service.yml文件作为共享配置,然后引入配置代码如下:

spring:
  application:
    name: provider
  profiles:
    active: dev
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml
        shared-dataids: allservice.yaml #配置要引入的配置
        refreshable-dataids: allservice.yaml #配置要实现动态配置刷新的配置
      discovery:
        cluster-name: BJ
    sentinel:
      transport:
        dashboard: localhost:8080

1.2.4 nacos 几个概念

命名空间(Namespace)
命名空间可用于进行不同环境的配置隔离。一般一个环境划分到一个命名空间
配置分组(Group)
配置分组用于将不同的服务可以归类到同一分组。一般将一个项目的配置分到一组
配置集(Data ID)
在系统中,一个配置文件通常就是一个配置集。一般微服务的配置就是一个配置集
 

2.分布式锁

2.1 分布式锁介绍

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。

在单体的应用开发场景中,在多线程的环境下,涉及并发同步的时候,为了保证一个代码块在同一时间只能由一个线程访问,我们一般可以使用synchronized语法和ReetrantLock去保证,这实际上是本地锁的方式。也就是说,在同一个JVM内部,大家往往采用synchronized或者Lock的方式来解决多线程间的安全问题。但在分布式集群工作的开发场景中,在JVM之间,那么就需要一种更加高级的锁机制,来处理种跨JVM进程之间的线程安全问题.

总之,对于分布式场景,我们可以使用分布式锁,它是控制分布式系统之间互斥访问共享资源的一种方式。比如说在一个分布式系统中,多台机器上部署了多个服务,当客户端一个用户发起一个数据插入请求时,如果没有分布式锁机制保证,那么那多台机器上的多个服务可能进行并发插入操作,导致数据重复插入,对于某些不允许有多余数据的业务来说,这就会造成问题。而分布式锁机制就是为了解决类似这类问题,保证多个服务之间互斥的访问共享资源,如果一个服务抢占了分布式锁,其他服务没获取到锁,就不进行后续操作。如下图:

分布式锁要具有一下特征:

  • 互斥性。在任意时刻,只有一个客户端能持有锁。
  • 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  • 具有容错性。只要大部分的 Redis 节点正常运行,客户端就可以加锁和解锁。
  • 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。


 分布式锁的核心是实现多进程之间互斥,而满足这一点的方式有很多,常见的有三种:

 2.2 Redisson 

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。

假如我们在微服务架构中,有个订单秒杀服务,要求同一个优惠券,一个用户只能下一单。在单机架构中,我们使用synchronized或者Lock的方式就可以解决这个问题,将查询数据库是否下过单和下单扣减库存过程锁在一块,只允许获得锁的一个线程进行访问。如果不加锁,假如高并发场景下,一百个线程同时访问并且都是同一个用户,然后就会出现多个线程先进行查询操作,如果数据库中没有该订单信息,然后这多个线程就会都符合要求进行下单扣减库存产生多个订单,就会违背一个用户只能下一单的情况。而在分布式中,因为多个服务都是以集群形式的存在存在多个jvm实例,synchronized或者Lock的方式只是针对的同一个JVM内部,这就需要分布式锁。这里使用Redission进行模拟,模拟在微服务集群高并发场景下多个用户线程下下单同一订单扣减库存情况。

2.2.1 Redisson 实践

导入依赖

      <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.19.0</version>
        </dependency>

代码如下:

本代码模拟根据订单id查询到订单信息,然后根据订单信息中的goodsId传递到商品微服务,进行对应商品的库存减一,然后返回修改后的商品信息 存储到订单信息对应商品Goods属性上。加分布式锁是保证在同一集群中不同微服务进程中的这个方法只能由获得锁的线程进行处理业务,由于是代码模拟,所以在设计代码的时候相对随意。

    @GetMapping("/order/pay/{id}")
    public Orders1 pay(@PathVariable("id") Long id){
        RLock lock = redissonClient.getLock("lockorder" + id);
        boolean b = lock.tryLock();
        if(!b) {
            return null;
        }
        try {
            Orders1 orders1 = orders1Mapper.selectById(id);
            Goods goods = feign.goodsservice(orders1.getGoodsId());
            orders1.setGoods(goods);
            return orders1;
        }finally {
            lock.unlock();
        }
    }

debug验证结果如下:

下面订单微服务集群为8080端口和9202端口,先访问8080端口,再访问9202端口,在debug环境下验证了我们的猜想。

 

 2.2.2 Redisson 原理

此章节引用网上相关描述

Redisson 这个框架对Redis分布式锁的实现原理图如下:

 1.获取锁
一个Redission客户端1要加锁,它首先会根据hash节点选择一台机器,紧接着就会发送一段lua脚本到redis上,比如加锁的那个锁key就是”mylock”,并且设置的时间是30秒,30秒后mylock锁就会被释放。
2.锁互斥机制
如果这个时候Redission客户端2来加锁,它也会会根据hash节点选择一台机器,然后执行了同样的一段lua脚本。
它首先回来判断《mylock》这个锁存在吗?如果存在则Redission客户端2会获得一个数字,这个数字就是mylock这个锁的剩余生存时间。
此时Redission客户端2就会进入到一个while循环,就是CAS不停的自旋尝试加锁,知道成功为止。
3.看门狗机制
如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。
为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。线程A拿到锁需要处理2秒,但是锁的超时时间只有1秒,也就是说锁超时的时候,业务还没处理完。这时候线程B就进来了又拿到锁,导致加锁跟解锁的时候并不是同一线程。看门狗的作用就是当遇到这种情况的时候,看门狗会定时去查看一下这个线程A是否还在执行任务,如果还在执行则给他继续延长时间。

4.可重入加锁机制
我们知道ReentrantLock是可重入锁,它的特点就是:同一个线程可以重复拿到同一个资源的锁,Redisson也能很好的满足这点。
Redisson客户端1获得mylock锁时,里面会有一个hash结构的数据,如下图所示:


 

上面这图的意思就是可重入锁的机制,它最大的优点就是相同线程不需要在等待锁,而是可以直接进行相应操作。


5.释放锁机制
如果发现加锁次数变为0了,那么说明这个Redisson客户端1不再持有锁了,Redisson客户端2就可以加锁了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/514657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTTPS协议详解

https是http over TLS&#xff08;transport security layer&#xff09;的缩写。也即说明http协议是不安全的&#xff0c;是TLS协议保证的安全。协议层级图如下: 我们常说https协议是安全的&#xff0c;主要是指两点&#xff1a; 第一&#xff0c;通信两端可以进行身份验证。…

复习一周,面了京东和百度,不小心都拿了Offer...

我个人情况是5年软件测试经验&#xff0c;在家复习了一周&#xff0c;面了京东和百度&#xff0c;都顺利拿下offer&#xff0c;下面是我的面试经历分享&#xff0c;希望能带来一些不一样的启发和帮助。 两家公司最常问的就是下面这些问题&#xff1a; 请介绍一下你之前做过哪些…

万用表位数的定义以及对应的ADC位数

万用表的精度通常会用几位半来描述&#xff1a; 比如大部分普通的万用表是 3 / 的精度&#xff0c;也就是俗称的3位半。 也就是说这个万用表最多显示4个数字&#xff0c;其中3位可以显示完整的0~9&#xff0c; 而这位是4个数字中的最高位&#xff0c;2代表只能显示0和1两个数…

【OAI】OAI5G核心网VPP-UPF网元分析

文章目录 VPP_UPF_CONFIG_GENERATION.mdVPP UPF Configuration GenerationEnvironment variablesInterfacesInterface Configuration ExamplesCentral UPFA-UPFI-UPFUL CL FEATURE_SET.mdVPP_UPG_CLI参考文献 VPP_UPF_CONFIG_GENERATION.md VPP UPF Configuration Generation …

(十三)地理数据库创建——进一步定义数据库①

地理数据库创建——进一步定义数据库① 目录 地理数据库创建——进一步定义数据库① 1.建立索引1.1建立属性索引1.2修改空间索引 2.创建子类和属性域2.1属性域2.2子类型2.3属性分割和合并2.4属性域操作2.4.1建立属性域2.4.2修改属性域2.4.3关联属性域 2.5子类型操作2.5.1建立子…

动态规划--青蛙跳台阶

青蛙跳台阶 前言青蛙跳台阶题目最优解结构性质画图分析发现规律验证规律 动规表达式青蛙跳台阶与斐波那契数列的不同之处 递归实现代码实现测试结果递归过程画图分析 非递归实现代码实现对比分析 前言 斐波那契数列每次学都有不一样的体会&#xff0c;从最开始简单理解就是&am…

无监督域适应 (UDA)(2)

本帖介绍UDA 的一个分支&#xff1a;bi-classifier adversarial learning。 一、回顾 在介绍 bi-classifier adversarial learning 之前&#xff0c;先来回忆一下 adversarial generation framework, 因为前者是基于后者的改进。 如图1所示&#xff0c;左边表示的是1&#xf…

DeepSORT 论文精读

摘要 SORT&#xff08;Simple Online and Realtime Tracking&#xff09; we integrate appearance information to improve the performance of SORT 集成外观信息来提高SORT的表现 we are able to track objects through longer periods of occlusions, effectively reduci…

JVM学习05:内存模型

JVM学习05&#xff1a;内存模型 1、java内存模型 很多人将java 内存结构与java 内存模型傻傻分不清&#xff0c;java 内存模型是 **Java Memory Model&#xff08;JMM&#xff09;**的意思。 JMM 定义了一套在多线程读写共享数据时&#xff08;成员变量、数组&#xff09;时…

UE4/5对背景音乐的调整设置

音乐是一个游戏必不可少的因素。 而在游戏设置中&#xff0c;必不可少的就有对背景音乐的声音大小进行设置&#xff0c;而我们需要的就是如何对背景音乐进行设置&#xff1a; 准备两个蓝图&#xff0c;分别是音效类和音效类混合。 然后打开音效类&#xff0c;我们可以看见下图…

如何用postman进行http接口测试,这篇文章绝对会颠覆你的认知

目录 前言 优点&#xff1a; 1、什么是POSTMAN 2、新建一个项目 2、新增一个用例 3、添加请求信息 4、post请求参数 5、添加头信息 6、预处理和结果检查 7、全局变量与环境变量 8、导出用例为代码 9、批量执行用例 前言 HTTP的接口测试工具有很多&#xff0c;可以进…

贪心法——黑白连线问题

一、问题描述 黑白连线Time Limit: 1000 MSMemory Limit: 1000 KB Description 给定直线上2n个点的序列P[1,2,… ,2n]&#xff0c;每个点P[i]要么是白点要么是黑点&#xff0c;其中共有n个白点和n个黑点&#xff0c; 相邻两个点之间距离均为1&#xff0c;请设计一个算法将每…

第六章:C语言的数组

在我的生活中&#xff0c;有许许多多的东西&#xff0c;有强迫症的小伙伴们&#xff0c;喜欢把它们分类到一个地方保存&#xff0c;这样一来&#xff0c;用的时候就按分类的形式来找自己需要的东西&#xff0c;而C语言也是如此&#xff0c;当有多个整形的数字是&#xff0c;就可…

steam搬砖详细解说,CSGO游戏搬砖的18个疑问?

看到这边文章进来的都是想了解steam搬砖&#xff0c;做个副业&#xff0c;我希望你可以认真把这个看完再考虑要不要做&#xff0c;适不适合自己去做&#xff0c;首先steam搬砖这个项目是需要有周转本金的&#xff0c;因为需要购买饰品道具&#xff0c;至于多少&#xff0c;这个…

7种《软件测试用例设计方法》解读及工作场景解析

1、等价类划分法 等价类划分法是一种将输入、输出、内部值等划分为若干个等价类的黑盒测试设计技术。在这种方法中&#xff0c;我们假设同一等价类的数据会被程序以相同的方式处理。 例如&#xff1a;一个允许输入年龄的程序&#xff0c;允许的年龄范围是1到100。在这种情况下…

Vue Test Utils前端单元测试

含义 单元测试&#xff08;unit testing&#xff09;&#xff0c;是指对软件中的最小可测试单元进行检查和验证。在提供了经过测试的单元的情况下&#xff0c;系统集成过程将会大大地简化。流行框架 Mocha (https://mochajs.cn/)、Jest (https://www.jestjs.cn/) Mocha Chai…

asp.net web api 后端服务器在调试时跨域问题的解决方案

跨域在发布时&#xff0c;在iis设置中 https://www.cnblogs.com/babietongtianta/p/6488985.html 在开发调试时&#xff0c;program.cs中添加 和各种方法&#xff0c;都不可以。 后来在iisexpress中设置&#xff0c;解决了。 在右下角iisexpress 右键 双击打开applicationho…

PCL学习十:Segmentation-分割

参考引用 Point Cloud Library黑马机器人 | PCL-3D点云 PCL点云库学习笔记&#xff08;文章链接汇总&#xff09; 1. 引言 点云分割是根据空间、几何和纹理等特征对点云进行划分&#xff0c;使得同一划分区域内的点云拥有相似的特征。点云的有效分割往往是许多应用的前提&#…

【OAI】部署5GSA独立组网网络切片例程及例程解析

文章目录 摘要引言关键技术介绍5G核心网核心网网元功能 网络切片OAIDocker官方例程详解整体介绍具体详解网络切片架构部署概览与说明1-41.预先准备5.部署OAI 5G核心网6.获取基站仿真docker镜像7.部署基站仿真8.通信测试9.分析结果10. 使用多切片的UE11. 解除部署11.1解除RAN部署…

面了一个4年经验的测试员,一问三不知还反过来怼我?

金三银四期间&#xff0c;我们公司也开始大量招人了&#xff0c;我这次是公司招聘的面试官之一&#xff0c;主要负责一些技术上的考核&#xff0c;这段时间还真让我碰到了不少奇葩求职者 昨天公司的HR小席刚跟我吐槽&#xff1a;这几个星期没有哪天不加班的&#xff01;各种招…