SpringCloud之Config配置中心與Redis分布式鎖詳解
1.服務配置中心
1.1 服務配置中心介紹
首先我們來看一下,微服務架構下關于配置文件的一些問題:
1.配置文件相對分散。在一個微服務架構下,配置文件會隨著微服務的增多變的越來越多,而且分散在各個微服務中,不好統(tǒng)─配置和管理。
⒉.配置文件無法區(qū)分環(huán)境。微服務項目可能會有多個環(huán)境,例如︰測試環(huán)境、預發(fā)布環(huán)境、生產(chǎn)環(huán)境。每一個環(huán)境所使用的配置理論上都是不同的,一旦需要修改,就需要我們?nèi)ジ鱾€微服務下手動維護,這比較困難。
3.配置文件無法實時更新。我們修改了配置文件之后,必須重新啟動微服務才能使配置生效,這對一個正在運行的項目來說是非常不友好的。
基于上面這些問題,我們就需要配置中心的加入來解決這些問題。
配置中心的思路是:
1.首先把項目中各種配置全部都放到一個集中的地方進行統(tǒng)—管理,并提供—套標準的接口。
2.當各個服務需要獲取配置的時候,就來配置中心的接口拉取自己的配置。
3..當配置中心中的各種參數(shù)有更新的時候,也能通知到各個服務實時的過來同步最新的信息,使之動態(tài)更新
當加入了服務配置中心之后,我們的系統(tǒng)架構圖會變成下面這樣:

1.2 Nacos Config 實踐
使用nacos作為配置中心,其實就是將nacos當做一個服務端,將各個微服務看成是客戶端,我們將各個微服務的配置文件統(tǒng)一存放在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作為配置文件。
配置文件優(yōu)先級從高到低為:
bootstrap.properties>bootstrap.yml>application.properties>application.yml
這里舉例為訂單微服務,首先新建個bootstrap.yml文件,然后配置如下:
spring:
application:
name: provider
profiles:
active: dev #環(huán)境標識
cloud:
nacos:
server-addr: localhost:8848
config:
file-extension: yaml #配置文件格式
discovery:
cluster-name: BJ
sentinel:
transport:
dashboard: localhost:8080然后在nacos配置文件中配置Data ID為bootstrap中配置訂單微服務名+環(huán)境標識+配置文件格式。如下圖;

1.2.2 Nacos 配置動態(tài)刷新
實現(xiàn)在配置中心修改配置文件內(nèi)容后,程序內(nèi)部引用可以自動刷新,我們可以在自己創(chuàng)建的DataId配置文件中,更改項:
config: appName: product
硬編碼方式
@GetMapping("/test")
public String test(){
String property = configurableApplicationContext.getEnvironment().getProperty("config.appName");
return property;
}注解方式
@RestController
@RefreshScope /* 只需要在需要動態(tài)讀取配置的類上添加此注解就可以 */
public class UserController {
@Value("${config.appName}")
private String appName;
@GetMapping("/test")
public String test(){
return appName;
}
}1.2.3 配置共享
當配置越來越多的時候,我們就發(fā)現(xiàn)有很多配置是重復的,這時候就考慮可不可以將公共配置文件提取出來,然后實現(xiàn)共享。共享存在兩種場景:同一微服務,不同場景(namespace)下共享;不同微服務之間共享。
同一微服務,不同場景下共享配置
比如上面的訂單微服務,開發(fā)環(huán)境的配置文件為provider-dev.yaml,測試環(huán)境的配置文件為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 #配置要實現(xiàn)動態(tài)配置刷新的配置
discovery:
cluster-name: BJ
sentinel:
transport:
dashboard: localhost:80801.2.4 nacos 幾個概念
命名空間(Namespace)
命名空間可用于進行不同環(huán)境的配置隔離。一般一個環(huán)境劃分到一個命名空間
配置分組(Group)
配置分組用于將不同的服務可以歸類到同一分組。一般將一個項目的配置分到一組
配置集(Data ID)
在系統(tǒng)中,一個配置文件通常就是一個配置集。一般微服務的配置就是一個配置集

2.分布式鎖
2.1 分布式鎖介紹
分布式鎖:滿足分布式系統(tǒng)或集群模式下多進程可見并且互斥的鎖。
在單體的應用開發(fā)場景中,在多線程的環(huán)境下,涉及并發(fā)同步的時候,為了保證一個代碼塊在同一時間只能由一個線程訪問,我們一般可以使用synchronized語法和ReetrantLock去保證,這實際上是本地鎖的方式。也就是說,在同一個JVM內(nèi)部,大家往往采用synchronized或者Lock的方式來解決多線程間的安全問題。但在分布式集群工作的開發(fā)場景中,在JVM之間,那么就需要一種更加高級的鎖機制,來處理種跨JVM進程之間的線程安全問題.
總之,對于分布式場景,我們可以使用分布式鎖,它是控制分布式系統(tǒng)之間互斥訪問共享資源的一種方式。比如說在一個分布式系統(tǒng)中,多臺機器上部署了多個服務,當客戶端一個用戶發(fā)起一個數(shù)據(jù)插入請求時,如果沒有分布式鎖機制保證,那么那多臺機器上的多個服務可能進行并發(fā)插入操作,導致數(shù)據(jù)重復插入,對于某些不允許有多余數(shù)據(jù)的業(yè)務來說,這就會造成問題。而分布式鎖機制就是為了解決類似這類問題,保證多個服務之間互斥的訪問共享資源,如果一個服務搶占了分布式鎖,其他服務沒獲取到鎖,就不進行后續(xù)操作。如下圖:

分布式鎖要具有一下特征:
- 互斥性。在任意時刻,只有一個客戶端能持有鎖。
- 不會發(fā)生死鎖。即使有一個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證后續(xù)其他客戶端能加鎖。
- 具有容錯性。只要大部分的 Redis 節(jié)點正常運行,客戶端就可以加鎖和解鎖。
- 解鈴還須系鈴人。加鎖和解鎖必須是同一個客戶端,客戶端自己不能把別人加的鎖給解了。

分布式鎖的核心是實現(xiàn)多進程之間互斥,而滿足這一點的方式有很多,常見的有三種:

2.2 Redisson
Redisson是一個在Redis的基礎上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務,其中就包含了各種分布式鎖的實現(xiàn)。
假如我們在微服務架構中,有個訂單秒殺服務,要求同一個優(yōu)惠券,一個用戶只能下一單。在單機架構中,我們使用synchronized或者Lock的方式就可以解決這個問題,將查詢數(shù)據(jù)庫是否下過單和下單扣減庫存過程鎖在一塊,只允許獲得鎖的一個線程進行訪問。如果不加鎖,假如高并發(fā)場景下,一百個線程同時訪問并且都是同一個用戶,然后就會出現(xiàn)多個線程先進行查詢操作,如果數(shù)據(jù)庫中沒有該訂單信息,然后這多個線程就會都符合要求進行下單扣減庫存產(chǎn)生多個訂單,就會違背一個用戶只能下一單的情況。而在分布式中,因為多個服務都是以集群形式的存在存在多個jvm實例,synchronized或者Lock的方式只是針對的同一個JVM內(nèi)部,這就需要分布式鎖。這里使用Redission進行模擬,模擬在微服務集群高并發(fā)場景下多個用戶線程下下單同一訂單扣減庫存情況。
2.2.1 Redisson 實踐
導入依賴
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.19.0</version>
</dependency>代碼如下:
本代碼模擬根據(jù)訂單id查詢到訂單信息,然后根據(jù)訂單信息中的goodsId傳遞到商品微服務,進行對應商品的庫存減一,然后返回修改后的商品信息 存儲到訂單信息對應商品Goods屬性上。加分布式鎖是保證在同一集群中不同微服務進程中的這個方法只能由獲得鎖的線程進行處理業(yè)務,由于是代碼模擬,所以在設計代碼的時候相對隨意。
@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環(huán)境下驗證了我們的猜想。


2.2.2 Redisson 原理
此章節(jié)引用網(wǎng)上相關描述
Redisson 這個框架對Redis分布式鎖的實現(xiàn)原理圖如下:

1.獲取鎖
一個Redission客戶端1要加鎖,它首先會根據(jù)hash節(jié)點選擇一臺機器,緊接著就會發(fā)送一段lua腳本到redis上,比如加鎖的那個鎖key就是”mylock”,并且設置的時間是30秒,30秒后mylock鎖就會被釋放。
2.鎖互斥機制
如果這個時候Redission客戶端2來加鎖,它也會會根據(jù)hash節(jié)點選擇一臺機器,然后執(zhí)行了同樣的一段lua腳本。
它首先回來判斷《mylock》這個鎖存在嗎?如果存在則Redission客戶端2會獲得一個數(shù)字,這個數(shù)字就是mylock這個鎖的剩余生存時間。
此時Redission客戶端2就會進入到一個while循環(huán),就是CAS不停的自旋嘗試加鎖,知道成功為止。
3.看門狗機制
如果負責儲存這個分布式鎖的Redisson節(jié)點宕機以后,而且這個鎖正好處于鎖住的狀態(tài)時,這個鎖會出現(xiàn)鎖死的狀態(tài)。
為了避免這種情況的發(fā)生,Redisson內(nèi)部提供了一個監(jiān)控鎖的看門狗,它的作用是在Redisson實例被關閉前,不斷的延長鎖的有效期。線程A拿到鎖需要處理2秒,但是鎖的超時時間只有1秒,也就是說鎖超時的時候,業(yè)務還沒處理完。這時候線程B就進來了又拿到鎖,導致加鎖跟解鎖的時候并不是同一線程??撮T狗的作用就是當遇到這種情況的時候,看門狗會定時去查看一下這個線程A是否還在執(zhí)行任務,如果還在執(zhí)行則給他繼續(xù)延長時間。
4.可重入加鎖機制
我們知道ReentrantLock是可重入鎖,它的特點就是:同一個線程可以重復拿到同一個資源的鎖,Redisson也能很好的滿足這點。
Redisson客戶端1獲得mylock鎖時,里面會有一個hash結構的數(shù)據(jù),如下圖所示:


上面這圖的意思就是可重入鎖的機制,它最大的優(yōu)點就是相同線程不需要在等待鎖,而是可以直接進行相應操作。
5.釋放鎖機制
如果發(fā)現(xiàn)加鎖次數(shù)變?yōu)?了,那么說明這個Redisson客戶端1不再持有鎖了,Redisson客戶端2就可以加鎖了。
以上就是SpringCloud之Config配置中心與Redis分布式鎖詳解的詳細內(nèi)容,更多關于SpringCloud Config配置中心與Redis分布式鎖的資料請關注腳本之家其它相關文章!
相關文章
Java ffmpeg 實現(xiàn)視頻加文字/圖片水印功能(示例代碼)
本文介紹了使用Java和ffmpeg庫實現(xiàn)視頻加文字或圖片水印的方法,通過引入依賴代碼和示例,詳細說明了如何將文字水印和圖片水印添加到視頻中,為需要在視頻中加入水印的開發(fā)者提供了實用的指導,這種方法不僅增強了視頻內(nèi)容的版權保護,也為視頻編輯提供了更多的可能性2024-10-10
Java 多層嵌套JSON類型數(shù)據(jù)全面解析
這篇文章主要介紹了Java 多層嵌套JSON類型數(shù)據(jù)全面解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
解決eclipse中maven引用不到已經(jīng)存在maven中jar包的問題
這篇文章主要介紹了解決eclipse中maven引用不到已經(jīng)存在maven中jar包的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
springboot @RequiredArgsConstructor的概念與使用方式
這篇文章主要介紹了springboot @RequiredArgsConstructor的概念與使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-09-09

