摘要:運行在上的微服務服務發(fā)現與注冊在上一節(jié)中,我們學習了如何在上構建一個風格的微服務。接下來,我們將學習如何把運行在上的微服務暴露在服務中心上,以便客戶端的調用。資源服務在關閉時需要將服務實例在服務中心進行注銷操作。響應用戶的終止。
運行在 Docker 上的微服務 - 服務發(fā)現與注冊
tags: Docker Microservice RESTful etcd
Author: Andy Ai
Weibo: NinetyH
GitHub: https://github.com/aiyanbo/docker-restful-demo
在 上一節(jié) 中,我們學習了如何在 Docker 上構建一個 RESTful 風格的微服務。接下來,我們將學習如何把運行在 Docker 上的微服務暴露在服務中心上,以便客戶端的調用。
etcdetcd 是一個分布式,一致性的 k-v 存儲系統(tǒng),用于共享配置和服務發(fā)現。其特性是:
簡單: 可使用 curl 訪問的用戶 API(HTTP+JSON)
安全: 可選的SSL客戶端證書認證
快速: 單實例每秒 1000 次寫操作
可靠: 使用Raft保證一致性
etcd 使用 go 語言實現,并通過 Raft 一致性算法處理日志復制以保證強一致性。
在這個章節(jié)中,我們使用 etcd 作為服務注冊中心。
架構服務注冊 & 發(fā)現 Step0. 啟動 etcd注冊 & 服務發(fā)現
1. etcd registry 做為服務中心,提供注冊與服務發(fā)現。
2. 資源服務在準備完畢之后將服務實例注冊到服務中心。
3. 客戶端到服務注冊中心根據服務名稱獲取資源服務的地址。
4. 客戶端獲取資源服務的地址后,調用資源服務。
5. 資源服務在關閉時需要將服務實例在服務中心進行注銷操作。
etcd 提供了 Docker Image, 我們將使用 Docker 運行一個 etcd:
bashdocker run -d -p 4001:4001 coreos/etcd:v0.4.6 -name myetcd
測試 etcd 服務:
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 客戶端
xmlStep2. 微服務啟動完成時注冊到服務中心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 里面查看更多的接口使用。
調用 mousio.etcd4j.EtcdClient 向 etcd 注冊服務:
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. 查看服務中心里的服務Note:
注冊到服務中的key有以下幾個部分組成:
1. registry: 服務中心 Root
2. stacks: 服務名稱
3. v1: 服務的版本
4. instanceId: 服務的實例 ID
bash$ curl http://192.168.59.103:4001/v2/keys/registry/stacks/v1
如果服務成功注冊,你可以看到像下面這樣的結果:
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. 微服務關閉時注銷實例
資源服務實例在關閉時應該在服務中心進行注銷操作,否則客戶端就會拿到一個不可用的服務。
有一種簡單的方式是在程序的 Runtime.shutdownHook 里面添加一個注銷線程,像下面這樣:
javaRuntime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { etcd.delete(serviceInstanceKey).send(); } catch (IOException e) { e.printStackTrace(); } } });暴露公共 IP
上面我們已經成功地使用 etcd 為我們的服務進行了注冊跟暴露,但是我們實例在暴露自己的位置的時候卻是 "value": "http://172.17.0.5:9998/"。它暴露的是 docker 內部的一個 ip,不是公共 ip 會還是會導致客戶端不能訪問服務。這時我們可以使用 docker 的環(huán)境變量來解決這個問題。
在 docker 中,我們需要使用 ENV 來定義一個環(huán)境變量。
# host 的默認值為 0.0.0.0 ENV host 0.0.0.0
在程序中,我們要使用 System.getenv("host") 來讀取 docker 的環(huán)境變量。
在 docker 運行中,我們使用 -e 來覆蓋 Dockerfile 中 host 的環(huán)境變量值。
shdocker run -d -p 9998:9998 -e "host=192.168.59.103" docker-restful-demo高階
在 JVM 中,調用 shutdown hooks 有以下幾種情況:
1. 程序正常終止,最后的 non-daemon 線程退出。
2. 調用 System.exit 方法退出。
3. 響應用戶的終止。例如,輸入 Ctrl + C;使用 kill 命令殺死 JVM 進程(kill -9 不會);系統(tǒng)的全局事件:用戶的注銷,操作系統(tǒng)的 shutdown。
最底層的 java.lang.Shutdown 只運行 10 個 shutdown hook,但是使用 java.lang.Runtime.addShutdownHook 添加的的 shutdown hook 經過 java.lang.ApplicationShutdownHooks 包裝后并沒有限制。java.lang.ApplicationShutdownHooks 是 java.lang.Shutdown 的一個子 shutdown hook。
在程序被上面的幾種方法正常關閉下,JVM 會順利的執(zhí)行 shutdown hooks。但是在非正常情況下,例如:kill -9;系統(tǒng)突然斷電并不會調用 shutdown hooks。那么這樣就會導致資源服務已經不能提供服務了,但是由于這些原因沒有在服務中心注銷,同樣地會讓客戶端拿到一個不可用的地址列表。資源服務器的網絡中斷也會有同樣的問題。
我們可以使用一種很通用的方法解決這個問題:發(fā)送心跳包。具體的步驟為:
使用 etcd 的 TTL 接口設置key 的存活時間為 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 將服務實例的信息重新注冊到 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...
未經同意不可轉載, 轉載需保留原文鏈接與作者署名。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/26419.html
摘要:平臺上的微服務架構應用再來看一下我眼中的基于當前最流行的微服務架構的設計是什么樣的,即我們平臺上要運行的典型應用是什么樣的。 showImg(https://segmentfault.com/img/remote/1460000010900878); 8月19日的數人云Container Meetup上,張龍老師做了《基于Kubernetes的PaaS平臺的設計和思考》的精彩分享,分別...
摘要:個推針對服務場景,基于和搭建了微服務框架,提高了開發(fā)效率。三容器化在微服務落地實踐時我們選擇了,下面將詳細介紹個推基于的實踐。 2016年伊始Docker無比興盛,如今Kubernetes萬人矚目。在這個無比需要創(chuàng)新與速度的時代,由容器、微服務、DevOps構成的云原生席卷整個IT界。個推針對Web服務場景,基于OpenResty和Node.js搭建了微服務框架,提高了開發(fā)效率。在微服...
摘要:個推針對服務場景,基于和搭建了微服務框架,提高了開發(fā)效率。三容器化在微服務落地實踐時我們選擇了,下面將詳細介紹個推基于的實踐。 2016年伊始Docker無比興盛,如今Kubernetes萬人矚目。在這個無比需要創(chuàng)新與速度的時代,由容器、微服務、DevOps構成的云原生席卷整個IT界。個推針對Web服務場景,基于OpenResty和Node.js搭建了微服務框架,提高了開發(fā)效率。在微服...
摘要:是一個相對比較新的微服務框架,年才推出的版本雖然時間最短但是相比等框架提供的全套的分布式系統(tǒng)解決方案。提供線程池不同的服務走不同的線程池,實現了不同服務調用的隔離,避免了服務器雪崩的問題。通過互相注冊的方式來進行消息同步和保證高可用。 Spring Cloud 是一個相對比較新的微服務框架,...
摘要:本文是網易容器云平臺的微服務化實踐系列文章的第一篇。網易容器云平臺的前身是網易應用自動部署平臺,它能夠利用云提供的基礎設施,實現包括構建和部署一體化在內的整個應用生命周期管理。目前網易云容器服務團隊以的方式管理著微服務,每周構建部署次數。 此文已由作者馮常健授權網易云社區(qū)發(fā)布。 歡迎訪問網易云社區(qū),了解更多網易技術產品運營經驗。 摘要:網易云容器平臺期望能給實施了微服務架構的團隊提供完...
閱讀 3329·2021-11-04 16:09
閱讀 3331·2021-09-23 11:49
閱讀 3904·2021-09-09 09:33
閱讀 3852·2021-08-18 10:22
閱讀 2130·2019-08-30 15:55
閱讀 3712·2019-08-30 15:53
閱讀 2747·2019-08-28 18:08
閱讀 977·2019-08-26 18:18