摘要:運(yùn)行在上的微服務(wù)服務(wù)發(fā)現(xiàn)與注冊(cè)在上一節(jié)中,我們學(xué)習(xí)了如何在上構(gòu)建一個(gè)風(fēng)格的微服務(wù)。接下來(lái),我們將學(xué)習(xí)如何把運(yùn)行在上的微服務(wù)暴露在服務(wù)中心上,以便客戶(hù)端的調(diào)用。資源服務(wù)在關(guān)閉時(shí)需要將服務(wù)實(shí)例在服務(wù)中心進(jìn)行注銷(xiāo)操作。響應(yīng)用戶(hù)的終止。
運(yùn)行在 Docker 上的微服務(wù) - 服務(wù)發(fā)現(xiàn)與注冊(cè)
tags: Docker Microservice RESTful etcd
Author: Andy Ai
Weibo: NinetyH
GitHub: https://github.com/aiyanbo/docker-restful-demo
在 上一節(jié) 中,我們學(xué)習(xí)了如何在 Docker 上構(gòu)建一個(gè) RESTful 風(fēng)格的微服務(wù)。接下來(lái),我們將學(xué)習(xí)如何把運(yùn)行在 Docker 上的微服務(wù)暴露在服務(wù)中心上,以便客戶(hù)端的調(diào)用。
etcdetcd 是一個(gè)分布式,一致性的 k-v 存儲(chǔ)系統(tǒng),用于共享配置和服務(wù)發(fā)現(xiàn)。其特性是:
簡(jiǎn)單: 可使用 curl 訪問(wèn)的用戶(hù) API(HTTP+JSON)
安全: 可選的SSL客戶(hù)端證書(shū)認(rèn)證
快速: 單實(shí)例每秒 1000 次寫(xiě)操作
可靠: 使用Raft保證一致性
etcd 使用 go 語(yǔ)言實(shí)現(xiàn),并通過(guò) Raft 一致性算法處理日志復(fù)制以保證強(qiáng)一致性。
在這個(gè)章節(jié)中,我們使用 etcd 作為服務(wù)注冊(cè)中心。
架構(gòu)服務(wù)注冊(cè) & 發(fā)現(xiàn) Step0. 啟動(dòng) etcd注冊(cè) & 服務(wù)發(fā)現(xiàn)
1. etcd registry 做為服務(wù)中心,提供注冊(cè)與服務(wù)發(fā)現(xiàn)。
2. 資源服務(wù)在準(zhǔn)備完畢之后將服務(wù)實(shí)例注冊(cè)到服務(wù)中心。
3. 客戶(hù)端到服務(wù)注冊(cè)中心根據(jù)服務(wù)名稱(chēng)獲取資源服務(wù)的地址。
4. 客戶(hù)端獲取資源服務(wù)的地址后,調(diào)用資源服務(wù)。
5. 資源服務(wù)在關(guān)閉時(shí)需要將服務(wù)實(shí)例在服務(wù)中心進(jìn)行注銷(xiāo)操作。
etcd 提供了 Docker Image, 我們將使用 Docker 運(yùn)行一個(gè) etcd:
bashdocker run -d -p 4001:4001 coreos/etcd:v0.4.6 -name myetcd
測(cè)試 etcd 服務(wù):
bash$ boot2docker ip 192.168.59.103 $ curl http://192.168.59.103:4001/v2/keys/ {"action":"get","node":{"key":"/","dir":true}}Step1. 在 pom.xml 加入 etcd 客戶(hù)端
xmlStep2. 微服務(wù)啟動(dòng)完成時(shí)注冊(cè)到服務(wù)中心2.7.0 org.mousio etcd4j ${etcd4j.version}
在這里,我們將使用到 etcd 的 put 接口:
bashcurl http://192.168.59.103:4001/v2/keys/registry/stacks/v1/$instance_id -XPUT -d value="$instance_address"
你可以在 etc api docs 里面查看更多的接口使用。
調(diào)用 mousio.etcd4j.EtcdClient 向 etcd 注冊(cè)服務(wù):
javafinal String instanceId = UUID.randomUUID().toString(); final String serviceInstanceKey = "registry/stacks/v1/" + instanceId; final EtcdClient etcd = new EtcdClient(UriBuilder.fromUri("http://192.168.59.103/").port(4001).build()); etcd.put(serviceInstanceKey, "http://" + host + ":9998/").send();
Step3. 查看服務(wù)中心里的服務(wù)Note:
注冊(cè)到服務(wù)中的key有以下幾個(gè)部分組成:
1. registry: 服務(wù)中心 Root
2. stacks: 服務(wù)名稱(chēng)
3. v1: 服務(wù)的版本
4. instanceId: 服務(wù)的實(shí)例 ID
bash$ curl http://192.168.59.103:4001/v2/keys/registry/stacks/v1
如果服務(wù)成功注冊(cè),你可以看到像下面這樣的結(jié)果:
json{ "action": "get", "node": { "key": "/registry/stacks/v1", "dir": true, "nodes": [ { "key": "/registry/stacks/v1/ee07bf3e-e9d3-4d04-8bb9-48fc38f16384", "value": "http://172.17.0.5:9998/", "modifiedIndex": 26, "createdIndex": 26 } ], "modifiedIndex": 26, "createdIndex": 26 } }Step4. 微服務(wù)關(guān)閉時(shí)注銷(xiāo)實(shí)例
資源服務(wù)實(shí)例在關(guān)閉時(shí)應(yīng)該在服務(wù)中心進(jìn)行注銷(xiāo)操作,否則客戶(hù)端就會(huì)拿到一個(gè)不可用的服務(wù)。
有一種簡(jiǎn)單的方式是在程序的 Runtime.shutdownHook 里面添加一個(gè)注銷(xiāo)線程,像下面這樣:
javaRuntime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { etcd.delete(serviceInstanceKey).send(); } catch (IOException e) { e.printStackTrace(); } } });暴露公共 IP
上面我們已經(jīng)成功地使用 etcd 為我們的服務(wù)進(jìn)行了注冊(cè)跟暴露,但是我們實(shí)例在暴露自己的位置的時(shí)候卻是 "value": "http://172.17.0.5:9998/"。它暴露的是 docker 內(nèi)部的一個(gè) ip,不是公共 ip 會(huì)還是會(huì)導(dǎo)致客戶(hù)端不能訪問(wèn)服務(wù)。這時(shí)我們可以使用 docker 的環(huán)境變量來(lái)解決這個(gè)問(wèn)題。
在 docker 中,我們需要使用 ENV 來(lái)定義一個(gè)環(huán)境變量。
# host 的默認(rèn)值為 0.0.0.0 ENV host 0.0.0.0
在程序中,我們要使用 System.getenv("host") 來(lái)讀取 docker 的環(huán)境變量。
在 docker 運(yùn)行中,我們使用 -e 來(lái)覆蓋 Dockerfile 中 host 的環(huán)境變量值。
shdocker run -d -p 9998:9998 -e "host=192.168.59.103" docker-restful-demo高階
在 JVM 中,調(diào)用 shutdown hooks 有以下幾種情況:
1. 程序正常終止,最后的 non-daemon 線程退出。
2. 調(diào)用 System.exit 方法退出。
3. 響應(yīng)用戶(hù)的終止。例如,輸入 Ctrl + C;使用 kill 命令殺死 JVM 進(jìn)程(kill -9 不會(huì));系統(tǒng)的全局事件:用戶(hù)的注銷(xiāo),操作系統(tǒng)的 shutdown。
最底層的 java.lang.Shutdown 只運(yùn)行 10 個(gè) shutdown hook,但是使用 java.lang.Runtime.addShutdownHook 添加的的 shutdown hook 經(jīng)過(guò) java.lang.ApplicationShutdownHooks 包裝后并沒(méi)有限制。java.lang.ApplicationShutdownHooks 是 java.lang.Shutdown 的一個(gè)子 shutdown hook。
在程序被上面的幾種方法正常關(guān)閉下,JVM 會(huì)順利的執(zhí)行 shutdown hooks。但是在非正常情況下,例如:kill -9;系統(tǒng)突然斷電并不會(huì)調(diào)用 shutdown hooks。那么這樣就會(huì)導(dǎo)致資源服務(wù)已經(jīng)不能提供服務(wù)了,但是由于這些原因沒(méi)有在服務(wù)中心注銷(xiāo),同樣地會(huì)讓客戶(hù)端拿到一個(gè)不可用的地址列表。資源服務(wù)器的網(wǎng)絡(luò)中斷也會(huì)有同樣的問(wèn)題。
我們可以使用一種很通用的方法解決這個(gè)問(wèn)題:發(fā)送心跳包。具體的步驟為:
使用 etcd 的 TTL 接口設(shè)置key 的存活時(shí)間為 5s。
bashcurl http://192.168.59.103:4001/v2/keys/registry/stacks/v1/$instance_id -XPUT -d value="$instance_address" -d ttl=5 { "action": "get", "node": { "key": "/registry/stacks/v1/72f9a7ba-f100-4638-a502-1541fc7d08f1", "value": "http://192.168.113.86:9998/", "expiration": "2015-06-30T07:20:47.485980615Z", "ttl": 5, "modifiedIndex": 45, "createdIndex": 45 } }
每 5s 將服務(wù)實(shí)例的信息重新注冊(cè)到 etcd。
javaetcd.put(serviceInstanceKey, "http://" + host + ":9998/").ttl(5).send();
參考資料Note
5s 視自己系統(tǒng)的情況而定。
https://github.com/coreos/etcd
http://java.dzone.com/articles/know-jvm-series-2-shutdown
http://www.infoq.com/cn/news/2014/07/etcd-cluster-discovery
https://coreos.com/docs/cluster-management/setup/cluster-discovery/
http://blog.gopheracademy.com/advent-2013/day-06-service-discovery-wit...
http://stackoverflow.com/questions/2541597/how-to-gracefully-handle-th...
未經(jīng)同意不可轉(zhuǎn)載, 轉(zhuǎn)載需保留原文鏈接與作者署名。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26419.html
摘要:平臺(tái)上的微服務(wù)架構(gòu)應(yīng)用再來(lái)看一下我眼中的基于當(dāng)前最流行的微服務(wù)架構(gòu)的設(shè)計(jì)是什么樣的,即我們平臺(tái)上要運(yùn)行的典型應(yīng)用是什么樣的。 showImg(https://segmentfault.com/img/remote/1460000010900878); 8月19日的數(shù)人云Container Meetup上,張龍老師做了《基于Kubernetes的PaaS平臺(tái)的設(shè)計(jì)和思考》的精彩分享,分別...
摘要:個(gè)推針對(duì)服務(wù)場(chǎng)景,基于和搭建了微服務(wù)框架,提高了開(kāi)發(fā)效率。三容器化在微服務(wù)落地實(shí)踐時(shí)我們選擇了,下面將詳細(xì)介紹個(gè)推基于的實(shí)踐。 2016年伊始Docker無(wú)比興盛,如今Kubernetes萬(wàn)人矚目。在這個(gè)無(wú)比需要?jiǎng)?chuàng)新與速度的時(shí)代,由容器、微服務(wù)、DevOps構(gòu)成的云原生席卷整個(gè)IT界。個(gè)推針對(duì)Web服務(wù)場(chǎng)景,基于OpenResty和Node.js搭建了微服務(wù)框架,提高了開(kāi)發(fā)效率。在微服...
摘要:個(gè)推針對(duì)服務(wù)場(chǎng)景,基于和搭建了微服務(wù)框架,提高了開(kāi)發(fā)效率。三容器化在微服務(wù)落地實(shí)踐時(shí)我們選擇了,下面將詳細(xì)介紹個(gè)推基于的實(shí)踐。 2016年伊始Docker無(wú)比興盛,如今Kubernetes萬(wàn)人矚目。在這個(gè)無(wú)比需要?jiǎng)?chuàng)新與速度的時(shí)代,由容器、微服務(wù)、DevOps構(gòu)成的云原生席卷整個(gè)IT界。個(gè)推針對(duì)Web服務(wù)場(chǎng)景,基于OpenResty和Node.js搭建了微服務(wù)框架,提高了開(kāi)發(fā)效率。在微服...
摘要:是一個(gè)相對(duì)比較新的微服務(wù)框架,年才推出的版本雖然時(shí)間最短但是相比等框架提供的全套的分布式系統(tǒng)解決方案。提供線程池不同的服務(wù)走不同的線程池,實(shí)現(xiàn)了不同服務(wù)調(diào)用的隔離,避免了服務(wù)器雪崩的問(wèn)題。通過(guò)互相注冊(cè)的方式來(lái)進(jìn)行消息同步和保證高可用。 Spring Cloud 是一個(gè)相對(duì)比較新的微服務(wù)框架,...
摘要:本文是網(wǎng)易容器云平臺(tái)的微服務(wù)化實(shí)踐系列文章的第一篇。網(wǎng)易容器云平臺(tái)的前身是網(wǎng)易應(yīng)用自動(dòng)部署平臺(tái),它能夠利用云提供的基礎(chǔ)設(shè)施,實(shí)現(xiàn)包括構(gòu)建和部署一體化在內(nèi)的整個(gè)應(yīng)用生命周期管理。目前網(wǎng)易云容器服務(wù)團(tuán)隊(duì)以的方式管理著微服務(wù),每周構(gòu)建部署次數(shù)。 此文已由作者馮常健授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。 摘要:網(wǎng)易云容器平臺(tái)期望能給實(shí)施了微服務(wù)架構(gòu)的團(tuán)隊(duì)提供完...
閱讀 3152·2021-11-04 16:09
閱讀 3107·2021-09-23 11:49
閱讀 3603·2021-09-09 09:33
閱讀 3605·2021-08-18 10:22
閱讀 2041·2019-08-30 15:55
閱讀 3625·2019-08-30 15:53
閱讀 2653·2019-08-28 18:08
閱讀 888·2019-08-26 18:18