日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
張開(kāi)濤:降級(jí)特技之配置中心

降級(jí)開(kāi)關(guān)我們需要通過(guò)配置方式來(lái)動(dòng)態(tài)開(kāi)啟/關(guān)閉,在應(yīng)用時(shí),首先要封裝一套應(yīng)用層API方便業(yè)務(wù)邏輯使用,對(duì)于開(kāi)關(guān)數(shù)據(jù)的存儲(chǔ)如果涉及的服務(wù)器/系統(tǒng)較少,則初期可以考慮使用配置文件配置。如果涉及的服務(wù)器/系統(tǒng)較多,則應(yīng)該使用配置中心進(jìn)行配置。實(shí)現(xiàn)時(shí)要做到不需要修改代碼,不需要重啟應(yīng)用可動(dòng)態(tài)配置開(kāi)關(guān)。

創(chuàng)新互聯(lián)一直秉承“誠(chéng)信做人,踏實(shí)做事”的原則,不欺瞞客戶,是我們最起碼的底線! 以服務(wù)為基礎(chǔ),以質(zhì)量求生存,以技術(shù)求發(fā)展,成交一個(gè)客戶多一個(gè)朋友!為您提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、成都網(wǎng)頁(yè)設(shè)計(jì)、小程序制作、成都網(wǎng)站開(kāi)發(fā)、成都網(wǎng)站制作、成都軟件開(kāi)發(fā)、app開(kāi)發(fā)定制是成都本地專業(yè)的網(wǎng)站建設(shè)和網(wǎng)站設(shè)計(jì)公司,等你一起來(lái)見(jiàn)證!

1. 應(yīng)用層API封裝

如下是我們抽象并封裝的開(kāi)關(guān)API。

 
 
 
 
  1. USER( 
  2.     "用戶信息", 
  3.    "user.not.call.backend", "是否不調(diào)用后端服務(wù)", 
  4.    "user. call.backend.rate.limit", "調(diào)用后端服務(wù)的限流", 
  5.    "user.redis.expire.seconds", "redis緩存過(guò)期時(shí)間"), 

里邊涉及到一兩個(gè)配置。

  • user.not.call.backend:是否回源調(diào)用后端用戶服務(wù)。如果不開(kāi)啟,那么只會(huì)訪問(wèn)緩存,不會(huì)將流量打到后端。
  • user.call.backend.ratio:調(diào)用后端服務(wù)的限流,比如配置100,即一秒只有100個(gè)請(qǐng)求會(huì)打到后端服務(wù),剩余請(qǐng)求如果緩存沒(méi)用命中時(shí),則直接返回空數(shù)據(jù)或錯(cuò)誤。
  • user.redis.expire.seconds:后端返回的用戶數(shù)據(jù)在緩存中緩存多久。

通過(guò)封裝后,我們可以很簡(jiǎn)單地使用這些API。

 
 
 
 
  1. if (Switches.USER.notCall()) { 
  2.     retur nnull; 

或者

 
 
 
 
  1. cacheService.set(CacheKeys.getUserKey(pin), info, Switches.USER.getExpiresInSeconds()); 

API實(shí)現(xiàn)是從配置文件獲取相關(guān)配置,如果沒(méi)有,則返回一個(gè)默認(rèn)值。

 
 
 
 
  1. public boolean notCall() { 
  2.     return DynamicConfigurer.getBoolean(callKey, false); 

或者

 
 
 
 
  1. public int getExpiresInSeconds() { 
  2.     return DynamicConfigurer.getInt(expiresKey, DEFAULT_EXPIRES_IN_ SECONDS); 

2. 配置文件實(shí)現(xiàn)開(kāi)關(guān)配置

使用properties文件作為配置文件,借助JDK 7 WatchService實(shí)現(xiàn)文件變更監(jiān)聽(tīng),實(shí)現(xiàn)代碼如下所示。

 
 
 
 
  1. static { 
  2.     try { 
  3.         filename= "application.properties"; 
  4.         resource= new ClassPathResource(filename); 
  5.         //監(jiān)聽(tīng)filename所在目錄下的文件修改、刪除事件 
  6.        watchService = FileSystems.getDefault().newWatchService(); 
  7.        Paths.get(resource.getFile().getParent()).register(watchService,StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE); 
  8.         properties= PropertiesLoaderUtils.loadProperties(resource); 
  9.     } catch(IOException e) {e.printStackTrace();} 
  10.     //啟動(dòng)一個(gè)線程監(jiān)聽(tīng)內(nèi)容變化,并重新載入配置 
  11.     Thread watchThread = new Thread(() -> { 
  12.         while(true) { 
  13.             try{ 
  14.                WatchKey watchKey = watchService.take(); 
  15.                for (WatchEvent event : watchKey.pollEvents()) { 
  16.                    if (Objects.equal(event.context().toString(), filename)){ 
  17.                         properties =PropertiesLoaderUtils.loadProperties (resource); 
  18.                         break; 
  19.                    } 
  20.                } 
  21.                watchKey.reset(); 
  22.             } catch (Exception e){e.printStackTrace();} 
  23.         } 
  24.     }); 
  25.    watchThread.setDaemon(true); 
  26.    watchThread.start(); 
  27.   
  28.     Runtime.getRuntime().addShutdownHook(newThread(() -> { 
  29.         try{ 
  30.             watchService.close(); 
  31.         } catch(IOException e) {e.printStackTrace();} 
  32.     })); 
  33.   
  • 使用WatchService監(jiān)聽(tīng)“application.properties”文件所在目錄內(nèi)容變化,包括修改、刪除事件。
  • 通過(guò)后臺(tái)線程實(shí)現(xiàn)阻塞等待內(nèi)容變化事件,一旦發(fā)現(xiàn)有內(nèi)容變更,如果是“application.properties”文件發(fā)生變更,則重新裝載配置文件。
  • JVM停止時(shí)記得關(guān)閉WatchService。

整體實(shí)現(xiàn)比較簡(jiǎn)單,然后就可以封裝Properties實(shí)現(xiàn)自己的開(kāi)關(guān)API了。通過(guò)配置文件的方式缺點(diǎn)是每次配置文件內(nèi)容變更需要將配置文件同步到服務(wù)器上,這點(diǎn)算是比較麻煩的,如果自動(dòng)部署系統(tǒng)支持動(dòng)態(tài)更改配置文件并同步用這種方式,那么也并不麻煩。只是如果要維護(hù)多個(gè)項(xiàng)目時(shí),則需要切換多個(gè)界面來(lái)操作。

3. 配置中心實(shí)現(xiàn)開(kāi)關(guān)配置

統(tǒng)一配置中心,或者叫分布式配置中心,目的是實(shí)現(xiàn)配置開(kāi)關(guān)的集中管理,要有配置后臺(tái)方便開(kāi)關(guān)的配置,對(duì)于一般公司來(lái)說(shuō)配置中心的維護(hù)要簡(jiǎn)單,不需要投入過(guò)多的人力來(lái)做這件事情,配置中心不管是采用拉取模式還是推送模式,要考慮到連接數(shù)和網(wǎng)絡(luò)帶寬可能帶來(lái)的風(fēng)險(xiǎn)和問(wèn)題。目前有一些開(kāi)源方案可以選擇,如Zookeeper、Diamond、Disconf、Etcd3、Consul。本文選擇了Consul,其支持多數(shù)據(jù)中心、服務(wù)發(fā)現(xiàn)、KV存儲(chǔ)等特性,而且使用簡(jiǎn)單,提供了簡(jiǎn)單的Web UI方便管理,更多介紹可以參考Nginx負(fù)載均衡部分。我們借助Consul的KV存儲(chǔ)特性來(lái)實(shí)現(xiàn)配置管理。

啟動(dòng)Consul Server

 
 
 
 
  1. ./consul agent -server -bootstrap-expect 1-data-dir /tmp/consul  -bind 0.0.0.0-client 0.0.0.0  -ui-dir ./ui/ 

HTTP API CRUD

● 新增/修改

 
 
 
 
  1. curl -X PUT -d 'true'  http://localhost:8500/v1/kv/item_tomcat/user.not.call.backend 
  2. curl -X PUT -d '30'  http://localhost:8500/v1/kv/item_tomcat / user.redis.expire.seconds 

item_tomcat是我們系統(tǒng)名,后邊是我們的配置名,Consul可以通過(guò)目錄層次實(shí)現(xiàn)多級(jí)配置。

● 查詢某個(gè)開(kāi)關(guān)

curl

http://localhost:8500/v1/kv/item_tomcat/user.not.call.backend

● 查詢某個(gè)系統(tǒng)的開(kāi)關(guān)

curl

http://localhost:8500/v1/kv/item_tomcat?recurse

通過(guò)添加recurse參數(shù)實(shí)現(xiàn)目錄樹(shù)遞歸查詢,可以得到如下結(jié)果。

 
 
 
 
  1. [{"LockIndex":0,"Key":"item_tomcat/user.not.call.backend","Flags":0,"Value":"ZmFsc2U=","CreateIndex":13009,"ModifyIndex":13192},{"LockIndex":0,"Key":"item_tomcat/user.redis.expire.seconds","Flags":0,"Value":"MzA=","CreateIndex":13015,"ModifyIndex":13144}] 

● 阻塞查詢某個(gè)系統(tǒng)的開(kāi)關(guān)

 
 
 
 
  1. curl “http://192.168.61.129:8500/v1/kv/item_tomcat?t=10s&recurse= true&index=13192” 

此處的index取列表ModifyIndex最大值,當(dāng)其中的修改值大于此index,則返回?cái)?shù)據(jù)。也可以添加“wait=10s”設(shè)置超時(shí)時(shí)間,超時(shí)后阻塞返回。

● 刪除某個(gè)開(kāi)關(guān)

curl -X DELETE

http://localhost:8500/v1/kv/item_tomcat/user.not. call. backend

● 刪除某個(gè)系統(tǒng)開(kāi)關(guān)

curl -X DELETE

http://localhost:8500/v1/kv/item_tomcat?recurse

整體使用比較簡(jiǎn)單,Consul Web UI提供了可視化配置,在啟動(dòng)時(shí),通過(guò)ui-dir指定下載的Web UI目錄即可,配置界面如下圖所示。

配置界面簡(jiǎn)潔,目前存在的一個(gè)缺點(diǎn)是沒(méi)有配置項(xiàng)的描述功能,在定義配置時(shí),要起一個(gè)好理解且清晰的名字。

4. 應(yīng)用代碼

接下來(lái)就需要在應(yīng)用代碼中引入配置中心了,代碼如下所示。

 
 
 
 
  1. private static transient Properties properties =null; 
  2. private static transient String system ="item_tomcat"; 
  3. static { 
  4.     Consul consul = Consul.builder() 
  5.            .withHostAndPort(HostAndPort.fromString("192.168.61.129:8500")) 
  6.            .withConnectTimeoutMillis(1000) 
  7.            .withReadTimeoutMillis(30 * 1000) 
  8.            .withWriteTimeoutMillis(5000).build(); 
  9.     final KeyValueClient keyValueClient = consul.keyValueClient(); 
  10.     final AtomicBoolean needBreak = new AtomicBoolean(true); 
  11.     Thread thread = new Thread(() -> { 
  12.        BigInteger index = BigInteger.ZERO; 
  13.         while(true){ 
  14.            Properties _properties = new Properties(); 
  15.             try{ 
  16.                //阻塞獲取item_tomcat下的數(shù)據(jù)(阻塞30秒),index是item_tomcat下的最后修改數(shù)據(jù)的修改index,為了實(shí)現(xiàn)阻塞 
  17.                //此處阻塞時(shí)間受readTimeoutMillis影響 
  18.                List values =keyValueClient.getValues(system, QueryOptions.blockSeconds(30,index).build()); 
  19.                for(Value value : values) { 
  20.                    _properties.put(value.getKey().substring(system.length()+ 1), value. getValueAsString().orNull()); 
  21.                    //獲取最大的一個(gè)最后修改index,實(shí)現(xiàn)KeyValueClient #getValues的阻塞訪問(wèn) 
  22.                     indexindex = index.max(BigInteger.valueOf(value.getModifyIndex ())); 
  23.                } 
  24.                properties = _properties; 
  25.            } catch (ConsulException e) { 
  26.                e.printStackTrace(); 
  27.                if(e.getCode() == 404) { //如果key不存在,休眠下 
  28.                     try { Thread.sleep(5000L); } catch(Exception e1) {} 
  29.                } 
  30.            } 
  31.             if(needBreak.get()== true) {break;} 
  32.         } 
  33.     }); 
  34.    thread.run();//先運(yùn)行一次 
  35.    needBreak.set(false); 
  36.    thread.setDaemon(true); 
  37.    thread.start(); 

● 在配置Consul時(shí),目前我們使用的IP/PORT,實(shí)際應(yīng)用時(shí)建議使用域名/VIP,記得配置相關(guān)的超時(shí)時(shí)間。

● KeyValueClient在獲取數(shù)據(jù)時(shí)使用拉取模式(長(zhǎng)輪詢),可以設(shè)置合理的阻塞時(shí)間(次時(shí)間受限于Consul配置的超時(shí)時(shí)間),選擇最大的ModifyIndex進(jìn)行阻塞等待。

● 當(dāng)ConsulException的code=404表示system在配置中心沒(méi)有任何配置。

● 在加載該類時(shí)先運(yùn)行一次拉取配置,然后啟動(dòng)后臺(tái)線程阻塞拉取最新配置。

Consul的一個(gè)缺點(diǎn)是無(wú)法進(jìn)行增量配置更新,如果訂閱配置的應(yīng)用很多,那么每次配置更新下發(fā)的量就非常大,如果有增量配置更新的話,則只需要把變化的下發(fā)即可。

到此集成Consul配置中心就完成了,此處只列出了核心代碼,還有一些異常情況需要大家處理,使得配置中心在應(yīng)用中做到高可用。

【本文是專欄作者張開(kāi)濤的原創(chuàng)文章,作者微信公眾號(hào):開(kāi)濤的博客( kaitao-1234567)】


本文標(biāo)題:張開(kāi)濤:降級(jí)特技之配置中心
文章源于:http://www.5511xx.com/article/coiijpj.html