search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

當我們聊Consul服務發現的時候我們在聊什麼

本文源自3月30『高效開發運維』微信群的在線分享,轉載請在文章開頭註明來自『高效開發運維』公眾號。加群學習請關注『高效開發運維』公眾號,並點擊菜單中的「加群學習」或直接回復「加群」。

隨著微服務概念深入人心,越來越多的解決方案選擇使用微服務架構,這類架構的共同點是服務數量多,因此種類繁多的服務之間如何互相訪問就變成了一個很現實的問題。目前比較流行的分散式存儲有:Consul, etcd, ZooKeeper。今天主要分享下如何基於Consul來實現服務發現。

關於服務發現及Consul

將應用部署到集群時,服務IP或埠是動態分配的,用戶訪問時不知道後端的IP及埠在訪問這些服務時,使用一定的機制動態發現服務的IP及埠就是服務發現(Service Discovery)。

Consul是一個服務發現和配置管理的工具,是具有分散式、高可用、高度可擴展的服務。

Consul的特性

服務發現

Consul客戶端可以提供其他服務的服務發現功能,使用dns和http,服務發現問題很容易被解決。

監控檢查

使用Consul可以提供任意數量的健康檢查功能,無論是服務狀態(web伺服器返回 http 200)還是本地節點的信息(內存利用率超過90%),這些信息都可以由操作員進行設置,並由服務發現組件將服務流量從不健康的組件中移開。

key/value存儲

Consul的kv存儲功能,通過http api可以很容易完成動態配置管理、協調服務、主選舉、功能標記等服務。

跨中心部署

Consul支持多數據中心感知,可以支撐任意數量的區域無需複雜配置。

節點

節點類型

  • server

    服務發現、健康檢查、數據一致性存儲,leader選舉機制,所以奇數部署

  • agent

    健康檢查

Consul節點退出

  • 正常退出(至關重要)

    節點通過信號正常關閉,接到信號的Consul會通知其他節點,正常離開後上面的服務和健康檢查將被移除

  • 異常退出

    沒有通過信號正常關閉的節點,其他節點會由於沒有接到信號,認為這個節點還是正常的,也不會移除其服務和健康檢查。本文主要分享服務發現和健康檢查兩個特性。

ansible批量部署Consul

為了更加方便快捷的部署,採用Consul進行docker化的方式實現,Consul本身安裝很簡單,只安裝二進位的包即可使用。首先從組件下載頁找到合適系統的二進位包下載,下載后將二進位的包拷貝安裝在對應的可被執行的目錄里,如:~/bin 或者 /usr/local/bin。Consul 還有web_ui,需要單獨下載,並在啟動指定目錄即可。

dockerfile

集群運行

Consul可以運行client和server 兩種節點模式,每個數據中心必須有一個server節點,但如果高可用,需要部署3個以上。其它Consul全部運行在client模式。客戶端連接會有一個非常輕的註冊過程,運行健康檢查併發給server節點。client運行在每個節點上。

ansible批量部署Consul server (agent與server類似)

Consul server ansible模板片段

Consul agent ansible模板片段

上面啟動的信息中每台主機啟動的參數不同的主要是IP,所以使用ansbile的時候就用到了一個小技巧,在ansible的hosts配置文件中給每條主機信息添加一個變數 ansible_ssh_host,在ansible運行中直接引用hosts配置中的變數,其它相對來說比較固定的參數,填寫到ansible的全局變數文件ansible/inventory/group_vars/all中,或執行playbook時傳入就可以了。

ansible hosts配置示例

base-Consul-master ansible role 片段

base-Consul-master playbook

調用playbook的執行腳本

調用playbook是可以指定主機或主機組

部署Consul master

指定ansible role中的tag 執行任務

ansible批量註冊服務健康檢查到Consul

Consul服務定義

Consul中的服務可以在啟動前就定義 ,提前寫好定義服務的配置文件放置到 Consul配置目錄Consul.d中, 如果這種方式需要更新,則需要重啟或發送SIGHUP信號給Consul ,不太方便操作,因此推薦使用Consul api的方式來註冊服務。註冊服務的信息主要包含id, name, port, address, check每個服務可以由多個ip可以有多個埠的服務組成。需要注意的是:每個服務可以有多個check,check可以是埠檢查、http檢查、腳本檢查。其中檢查腳本通常是自由做任何事情,以確定檢查的狀態。唯一的限制是,該退出代碼都必須遵守此約定:

  • Exit code 0 - 檢查結果是 passing

  • Exit code 1 - 檢查結果是 warning

  • 其它 Exit code - 檢查結果是 failing

註冊服務通常是通過agent來註冊,因為服務的健康檢查與所在Consul agent是綁定的,如果 Consul agent所有宿主機掛掉,就認為這台主機上的服務也是掛的。

Consul健康檢查參考:

ansible註冊服務及健康檢查到Consul agent模板reg_Consul.sh片段

註冊的服務有問題,需要刪除調用deregistry介面

刪除一個服務

刪除一個檢查

agent api 參考:注意:

  • 同一個服務 每個實例的id唯一

  • 同一個服務 每個檢查項的id唯一

ansible批量註冊服務到Consul

服務發現

Consul啟動后,並且服務集群狀態正常,就可以對外提供DNS或者HTTP API來查詢服務了。

http api

通過Consul server查詢服務列表信息

通過Consul server查詢單個服務信息

通過agent查詢服務服務

只查詢健康的服務

(不加passing參數會包含warning的服務,不包含critical的服務)

agent操作api參考 https://www.consul.io/docs/agent/http/agent.html

Consul dns服務發現

Consul自帶一套dns 服務,所以可以處理簡單的服務發現。通過dig命令查詢Consul dns中的服務解析, critical的服務不會解析

使用dnsmasp轉發Consul dns

Consul默認的dns服務埠是8600,常用的dns服務默認的埠為53,所以如果使用8600,不太方便,而且Consul 0.7.0版本后才支持修改默認Consul dns埠,就算可以修改Consul dns埠,但又可能會跟其它的dns服務衝突。

可以使用centos7自帶的服務dnsmasp來轉發Consul dns和其它dns服務在/etc/dnsmasq.d/dns-hosts.conf中添加 Consul dns地址

配置NetworkManager

在resolv.conf中添加search service.Consul和默認的dns server指定到本機,

這樣即可直接在宿主機使用dns訪問到Consul中的服務了,而且可以使用短域名訪問,例如:

使用registrator實現自動註冊服務

registrator通過在容器啟動時檢查容器來自動註冊和註銷任何Docker容器的服務。registrator支持自動註冊的服務包括Consul,etcd和SkyDNS 2github地址:

直接使用官方鏡像即可。

docker run方法

服務自動註冊的id name check等需要在被註冊的服務啟動環境變數指定。例如:

docker run -d --net host -p 5014:5014 -e SERVICE_5014_ID=cadivisor -e SERVICE_5014_NAME=cadivisor cadivisor

注意:使用Consul做服務發現一般為host模式啟動的服務,埠是固定的。由於埠問題,一台宿主機也只部署一個實例。host模式一般不添加 -p 或 --publish參數,但registrator 的默認註冊規則,是有--publish都會自動註冊到Consul, 所以host 模式 就算是不需要埠映射,也需要添加--publish參考指定埠,這樣registrator 就會把服務註冊到Consul了。

參考 :

haproxy配合Consul dns實現服務發現

haproxy做為PaaS平台服務的負載均衡服務,對外服務;配置backend服務時,配置的是Consul中的服務域名。

這裡有個坑,原來使用haproxy 1.5版本, 後端服務使用域名時,啟動后只解析一次(和nginx類似),這時如果解析到的服務掛掉,訪問haproxy頁面時會503。查詢官網得知haproxy 1.6支持了動態dns 域名解析的配置,后升級為haproxy 1.6。

下面是動態DNS解析相關的配置內容:

用戶訪問haproxy就會動態解析訪問後端Consul中的服務。

基於Consul dns,實現mysql高可用切換

數人云最初的Mysql主從切換是基於 haproxy+keepalived 來做高可用的。這種機制下,Mysql主從切換的簡單需求需要引入2個開源組件,架構上也非常複雜。為了減輕架構複雜度和可維護性,將主從切換改為了使用Consul進行主從切換。Mysql是安裝了兩台,一主一從,設置許可權時,主是讀寫的,從是普通用戶只讀許可權。通過將服務註冊到Consul來做健康檢查,Mysql Master和Slave註冊四個服務到Consul, 如下代碼:

正常情況mysql-vip.service.Consul解析到 主mysql ip。這裡分兩種情況切換到從解析:— 主Mysql掛掉后,ip解析到從mysql ip,mysql-vip 切換到從Mysql IP 。— 主庫的Consul 掛掉也會導致服務無法解析,即使 mysql-master正常,如果Consul掛掉也會被激活切換。

請注意:因為Mysql從是只讀的,相當於降級服務。

接下來再分享一下Consul實踐中遇到的一些坑。

Consul實踐遇到的坑

調用deregistry介面刪除Consul服務后,詭異的出現了

初期進行http api 調試測試時,註冊了一些服務到Consul, 後來想刪除就調用,ip:8500/v1/catalog/deregister 介面進行刪除,調用該介面返回成功。但過一會兒去web ui查詢, 發現剛才刪除的服務還在,後來查詢官方文檔,原來server端catalog和 agent端都有deregister介面,我們的服務都是通過agent註冊的,所以在catalog 刪除不生效,只能通過agent的 deregistry介面來刪除。

清理Consul持久化數據異常

測試Consul server服務的高可用,先停止其中一台Consul server節點的容器,並清理Consul 的持久化數據,其它服務的Consul節點正常,達到預期結果,後來嘗試恢復這個Consul server,恢復后發現從Consul ui查發現 少了一些服務節點,查詢過後,正好是清理數據的這台Consul server上的服務在 Consul 中消失了,因此又重新在這個節點進行相應的服務註冊才真正恢復正常。

健康檢查狀態碼的坑

健康檢查腳本中使用grep檢查結果內容,如果匹配則正常,不匹配為異常,例如: echo result|grep ok,有一次,一個服務節點異常,grep也沒有匹配,當時認為這樣就不會被解析了,後來發現這個服務ip還是會被解析,查詢問題發現grep 不匹配的error code 為1 ,code 1 只是warning ,還是會被解析,所以修改檢查腳本內容,如果不匹配,手動返回error code 2,之後這個異常服務才不解析。

使用registrator自動註冊的坑

在數人云的PaaS平台發布的服務,一般服務容器名稱都是隨機的,registrator 默認的自動註冊規則是把容器名註冊為 Consul中的service id,這樣在Consul就有可能同一個服務被註冊多次,實際上是同 個服務不同實例。所以需要在啟動容器的環境變數中指定SERVICE_xxx_NAME ,這樣registrator註冊的時候就不會同是有多個相同的服務但server name 的不同 ,同理,如果需要consul 中的 service id 保持 致,則需要啟動容 時指定SERVICE_xxx_ID。

registrator 默認 自動註冊的服務在consul中 帶健康檢查的,所以容器實例掛掉,consul的 頁面上是看不 出的,會導致consul dns解析到異常的容器實例 上,所以需要在啟動容 時需 要添加類似下面的環境變數。

Consul agent節點異常

部署客戶環境時遇到一個詭異的問題,有兩個節點總是異常,健康檢查這兩個節點時好時壞,大部分時間是壞的,少部分時間顯示正常狀態。

排查問題時,發現主機之間響應時間很快,Consul server 與Consul agnet 之間的Consul埠都是可以通的。

查詢Consul server日誌,看到 server 日誌中有error

以為是有埠漏開放了,telnet 測試后,發現Consul server到agent都是通的,谷歌下這個錯誤,發現有可能是因為沒有開通udp埠導致的,後來又使用nmap測試Consul相關的udp埠是不是開放的,測試后發現udp 果然沒有開通。於是就向客戶申請開通相應的udp埠,開通后,再進行測試,發現問題還是存在。

這就不得不再想其它辦法,後來又查詢異常的Consul agent節點日誌發現,發現Consul agent 也報類似的錯誤,乍一看跟server端的日誌是一樣的,但仔細研究發現關鍵問題,異常節點的agent報了很多訪問其它agent節點8301埠的 time out的日誌:

才發現agent不僅訪問server, 還需要訪問同級的其它agent 8301埠進行健康檢查,後來開放8301所有Consul節點的埠訪問后才正常。

比起另外兩個同樣流行的分散式存儲etcd和ZooKeeper, Consul從設計上就考慮到了很多服務發現的需求, 比如說健康檢查, 服務註冊, DNS等。所以基於Consul來實現服務發現的功能還是有很多的想象空間的。

QA環節

Q1:感謝老師!Consul, etcd, ZooKeeper能比較一下嗎?為什麼沒有選用后兩者呢?

A1:ZooKeeper 處理數據 不支持 resf api , 需要操作的時候比較繁瑣,功能也比較單一,etcd 服務功能也相對單一,需要依賴其它 組件 配合使用Consul 本身自帶服務發現、健康檢查 、dns解析 功能相對來說強大一些,不需要依賴其它的組件就可能實現很多功能

Q2:就服務發現和zk相比,會有多大的延遲?

A2: 就服務發現來說,Consul 支持 api 和 dns 兩個方式獲取 服務, dns 解析基本無消耗。 api 操作的話,具體的數據我沒有進行嚴格測試,但zk是java服務本身需要的內存比較多,java gc 垃圾回收也會影響一些性能。Consul 是go 語言開發性能會有一些優勢。

Q3: 這裡問一個不是很相關的問題,老師怎麼看待Docker和微服務更配這樣的說法?

A3: 以前是所有功能集成到一個服務中,微服務本身需要拆分服務,需要部署、更新、維護的服務數量會幾何增加,如果是傳統的方式運維的話,操作起來就是個挑戰,Docker化之後,部署、遷移、交付都會變簡單。

Q4:Consul最大承受多大規模,有瓶頸嗎?

Q4: 我沒有針對 Consul服務 做過壓力測試,我們一般是會對服務進行壓力測試,就現在我們部署的集群規模而言,支持幾百來的Consul 節點是沒有問題的。理論上可以更多。

Q5:內部的web服務怎麼註冊?用後台腳本周期性地檢測web服務正常后,再請求介面註冊服務嗎?失敗取消

A5: 如果 使用了 registrator ,docker服務啟動時,添加相應的環境變數,就會自動註冊到Consul,也會自動刪除,不過registrator偶爾異常情況會有不同步的現象,我們在 registrator 啟動時添加同步參數定時同步,如果沒有使用 registrator ,就需要自己處理註冊和刪除的邏輯,例如我們使用marathon /mesos 做為調試的核心基礎組件,可以監聽marathon 的事件獲取 容器實例 啟動在哪,刪除了哪些,就可以相應對 Consul做操作Consul 也支持異常服務定時清理,在註冊添加時添加DeregisterCriticalServiceAfter 參數 就可以

Q6:「每個數據中心必須有一個server節點,但如果高可用,需要部署3個以上」為啥一定要三個以上

A6: Consul server 節點也分為 leader 和 follower 節點,leader 選舉一般為基數選舉,1個就不是高可用了,所以最少3個,遵循2N+1 原則,支持宕機 N 個節點。

Q7: Consul能夠支撐多大的高併發系統?

A7: 這個問題跟上面的問題稍有些重合,其實高併發是指的業務,業務一般在 啟動、停止、遷移 、或業務之間相互訪問時 Consul 才會有些數據交互 ,Consul的健康檢查 和 訪問都是分攤到每個宿主機上, Consul 的壓力 對比業務來說可以忽略不計。

作者介紹

劉金燁,數人云運維工程師。早期做 Java 開發,後轉職為運維開發,曾就職於仙掌軟體、金山西山居,現就職於數人云。負責數人雲平台 Mesos/Marathon/Docker 環境維護、運維自動化建設。



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦