第一大家来看一下,微服务构造下关于配置文件的一些问题:
1.配置文件相对分散。在一个微服务构造下,配置文件会伴随微服务的增多变的愈加多,而且分散在每个微服务中,不好统─配置和管理。
⒉.配置文件没办法区别环境。微服务项目或许会有多个环境,比如︰测试环境、预发布环境、生产环境。每个环境所用的配置理论上都是不一样的,一旦需要修改,就需要大家去每个微服务下手工维护,这比较困难。
3.配置文件没办法实时更新。大家修改了配置文件之后,需要重新启动微服务才能使配置生效,这对一个正在运行的项目来讲是很不友好的。
基于上面这类问题,大家就需要配置中心的加入来解决这类问题。
配置中心的思路是:
1.第一把项目中各种配置全部都放到一个集中的地方进行统mdash;管理,并提供mdash;套标准的接口。
2.当每个服务需要获得配置的时候,就来配置中心的接口拉取我们的配置。
3..当配置中心中的各种参数有更新的时候,也能公告到每个服务实时的过来同步最新的信息,使之动态更新
当加入了服务配置中心之后,大家的系统构造图会变成下面如此:

用nacosplay作为配置中心,其实就是将nacosplay当做一个服务端,将每个微服务看成是推广客户端,大家将每个微服务的配置文件统一存放在nacosplay上,然后每个微服务从nacosplay上拉取配置即可。
1.2.1 Nacosplay config基础知识案例导入依靠
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacosplay-config/artifactId/dependency
在微服务中添加nacosplay config的配置,不可以用原来的application.yml作为配置文件,而是新建一个bootstrap.yml作为配置文件。
配置文件优先级从高到低为:
bootstrap.propertiesbootstrap.ymlapplication.propertiesapplication.yml
这里举例为订单微服务,第一新建个bootstrap.yml文件,然后配置如下:
spring:application:name:providerprofiles:active:dev#环境标识cloud:nacosplay:server-addr:localhost:8848config:file-extension:yaml#配置文件格式discovery:cluster-name:BJsentinel:transport:dashboard:localhost:8080
然后在nacosplay配置文件中配置Data ID为bootstrap中配置订单微服务名+环境标识+配置文件格式。如下图;

达成在配置中心修改配置文件内容后,程序内部引用可以自动刷新,大家可以在自己创建的DataId配置文件中,更改项:
config:appName:product
硬编码方法
@GetMapping(/test)publicStringtest(){Stringproperty=configurableApplicationContext.getEnvironment().getProperty(config.appName);returnproperty;}
注释方法
@RestController@RefreshScopepublicclassUserController{@Value(${config.appName})privateStringappName;@GetMapping(/test)publicStringtest(){returnappName;}}1.2.3 配置共享
当配置愈加多的时候,大家就发现有不少配置是重复的,这个时候就考虑能不能将公共配置文件提取出来,然后达成共享。共享存在两种场景:同一微服务,不同场景(namespace)下共享;不同微服务之间共享。
同一微服务,不同场景下共享配置
譬如上面的订单微服务,开发环境的配置文件为provider-dev.yaml,测试环境的配置文件为provider-test.yaml,同一微服务在不同场景下共享可以配置provider.yaml文件。
不同微服务之间共享共享配置
在nacosplay中新建all-service.yml文件作为共享配置,然后引入配置代码如下:
spring:application:name:providerprofiles:active:devcloud:nacosplay:server-addr:localhost:8848config:file-extension:yamlshared-dataids:allservice.yaml#配置要引入的配置refreshable-dataids:allservice.yaml#配置要达成动态配置刷新的配置discovery:cluster-name:BJsentinel:transport:dashboard:localhost:80801.2.4 nacosplay 几个定义
命名空间(Namespace)
命名空间可用于进行不同环境的配置隔离。一般一个环境划分到一个命名空间
配置分组(Group)
配置分组用于将不一样的服务可以归类到同一分组。一般将一个项目的配置分到一组
配置集(Data ID)
在系统中,一个配置文件一般就是一个配置集。一般微服务的配置就是一个配置集

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
在单体的应用开发场景中,在多线程的环境下,涉及并发同步的时候,为了保证一个代码块在同一时间只能由一个线程访问,大家一般可以用synchronized语法和ReetrantLock去保证,这事实上是当地锁的方法。也就是说,在同一个JVM内部,大伙总是使用synchronized或者Lock的方法来解决多线程间的安全问题。但在分布式集群工作的开发场景中,在JVM之间,那样就需要一种愈加高级的锁机制,来处置种跨JVM进程之间的线程安全问题.
总之,对于分布式场景,大家可以用分布式锁,它是控制分布式系统之间互斥访问共享资源的一种方法。譬如说在一个分布式系统中,多台机器上部署了多个服务,当推广客户端一个用户发起一个数据插入请求时,假如没分布式锁机制保证,那样那多台机器上的多个服务可能进行并发插入操作,致使数据重复插入,对于某些不允许有多余数据的业务来讲,这就会导致问题。而分布式锁机制就是为知道决类似这种问题,保证多个服务之间互斥的访问共享资源,假如一个服务抢占了分布式锁,其他服务没获得到锁,就不进行后续操作。如下图:

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

分布式锁的核心是达成多进程之间互斥,而满足这一点的方法有不少,容易见到的有三种:

Redisson是一个在Redis的基础上达成的Java驻内存数据网格(In-Memory Data Grid)。它不只提供了一系列的分布式的Java常用对象,还提供了很多分布式服务,其中就包括了各种分布式锁的达成。
倘若大家在微服务构造中,有个订单秒杀服务,需要同一个折扣券,一个用户只能下一单。在单机构造中,大家用synchronized或者Lock的方法就能解决这个问题,将查看数据库是不是下过单和下单扣减库存过程锁在一块,只允许获得锁的一个线程进行访问。假如不加锁,倘若高并发场景下,一百个线程同时访问并且都是同一个用户,然后就会出现多个线程先进行查看操作,假如数据库中没该订单信息,然后这多个线程就会都符合需要进行下单扣减库存产生多个订单,就会违背一个用户只能下一单的状况。而在分布式中,由于多个服务都是以集群形式的存在存在多个jvm实例,synchronized或者Lock的方法只不过针对的同一个JVM内部,这就需要分布式锁。这里用Redission进行模拟,模拟在微服务集群高并发场景下多个用户线程下下单同一订单扣减库存状况。
2.2.1 Redisson 实践导入依靠
dependencygroupIdorg.redisson/groupIdartifactIdredisson/artifactIdversion3.19.0/version/dependency
代码如下:
本代码模拟依据订单id查看到订单信息,然后依据订单信息中的goodsId传递到产品微服务,进行对应产品的库存减一,然后返回修改后的产品信息 存储到订单信息对应产品Goods属性上。加分布式锁是保证在同一集群中不同微服务进程中的这个办法只能由获得锁的线程进行处置业务,因为是代码模拟,所以在设计代码的时候相对随便。
@GetMapping(/order/pay/{id})publicOrders1pay(@PathVariable(id)Longid){RLocklock=redissonClient.getLock(lockorder+id);booleanb=lock.tryLock();if(!b){returnnull;}try{Orders1orders1=orders1Mapper.selectById(id);Goodsgoods=feign.goodsservice(orders1.getGoodsId());orders1.setGoods(goods);returnorders1;}finally{lock.unlock();}}
debug验证结果如下:
下面订单微服务集群为8080端口和9202端口,先访问8080端口,再访问9202端口,在debug环境下验证了大家的猜想。


此章节引用网上有关描述
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就能加锁了。





