隨著近幾年微服務(wù)與云計算的飛速發(fā)展,機器由物理機逐步變?yōu)榱颂摂M機,應(yīng)用服務(wù)由龐大的單體應(yīng)用逐漸變?yōu)榱巳舾蓚€微服務(wù)聯(lián)合組成的應(yīng)用集群,更新迭代的速度成倍上漲,傳統(tǒng)的部署模式已無法滿足開發(fā)日常更新需求,需要一套適合微服務(wù)的管理架構(gòu)。
技術(shù)棧及文檔
資源調(diào)度框架MESOS
應(yīng)用編排平臺Marathon
nginx動態(tài)修改upstream dyups
nginx動態(tài)修改upstream upsync
使用Mesos進行機器資源管理
首先,是機器資源的管理。在微服務(wù)的架構(gòu)中,原有的單體服務(wù)被拆分成了一個個獨立單元的應(yīng)用程序,這些服務(wù)體量較小,可以獨立運行在配置較小的機器上。為了故障隔離,我們會盡可能的把這些服務(wù)部署在不同的虛擬機上,這樣機器的數(shù)量會成倍增加。對于運維來說,每個新服務(wù)部署時,需要先查看現(xiàn)有機器的剩余資源是否滿足新服務(wù)的需求,有時可能因為評估不準(zhǔn)確造成來回擴容、遷移,或者資源浪費。
開始時,我們的架構(gòu)可能時這樣的
為了解決上面的問題,可以使用MESOS(布式資源管理框架),它可以讓我們像用一臺電腦(一個資源池)一樣使用整個數(shù)據(jù)中心。
mesos部署時分為master和agent兩個角色,當(dāng)然,你可以在同一臺機器啟動它們。
安裝Mesos前需要安裝zookeeper,mesos使用zk實現(xiàn)高可用和選舉,包括一個masterleader和幾個備份master避免宕機。
Mesos master負(fù)責(zé)管理各個Framework和Slave,并將Slave上的資源非配給各個Framework。
Mesos agent負(fù)責(zé)管理本節(jié)點上的各個MesosTask,為各個Executor分配資源(低版本為mesos-slave)。
- $ cat > /tmp/bintray-mesos-el.repo EOF
- #bintray-mesos-el - packages by mesos from Bintray
- [bintray-mesos-el]
- name=bintray-mesos-el
- baseurl=https://dl.bintray.com/apache/mesos/el7/x86_64
- gpgcheck=0
- repo_gpgcheck=0
- enabled=1
- EOF
- $ sudo mv /tmp/bintray-mesos-el.repo /etc/yum.repos.d/bintray-mesos-el.repo
- $ sudo yum update
- $ sudo yum install mesos
- $ tree /etc/mesos-master
- /etc/mesos-master/
- |-- hostname
- |-- ip
- |-- log_dir
- |-- quorum # quorum > (number of masters)/2
- `-- work_dir
- $ tree /etc/mesos-agent
- /etc/mesos-agent/
- |-- containerizers # 容器類型,默認(rèn) mesos,可以添加 docker,如: mesos,docker
- |-- hostname
- |-- ip
- |-- log_dir
- |-- master # master 地址,格式為 host:port 或
- zk://host1:port1,host2:port2,.../path 或 file:///path/to/file
- |-- resources # 設(shè)置總資源大小,可以設(shè)置小些來預(yù)留更多機器資源
- `-- work_dir
- $ cat /etc/mesos/zk # 設(shè)置 mesos 在zk 中的存儲目錄
- zk://192.168.100.9:2181,192.168.100.110:2181,192.168.100.234:2181/mesos
- $ systemctl start mesos-master
- $ systemctl start mesos-slave
當(dāng)mesos服務(wù)啟動后,agent會向master節(jié)點匯報機器資源,包括CPU、內(nèi)存、磁盤等。當(dāng)我們要發(fā)布一個服務(wù)時,只需要設(shè)置這個服務(wù)的CPU、內(nèi)存、磁盤參數(shù),mesosmaster會自動幫我們選擇有足夠資源的機器去運行,如下圖
我們將微服務(wù)的啟動都交給Mesos管理,這樣我們只需要關(guān)注整體資源即可。MESOS提供了UI界面,可以直接訪問mesosmaster的5050端口,查看集群資源使用情況??傮w使用情況及Agent節(jié)點使用情況
完成以上后,我們的架構(gòu)變成了這樣
使用Marathon進行微服務(wù)管理
Marathon是建立在Mesos上的私有PaaS平臺。它能自動處理硬件或者軟件故障,并確保每個應(yīng)用程序都永遠(yuǎn)在線。我們使用Marathon管理微服務(wù)有以下優(yōu)勢
支持容器和非容器,不受限于服務(wù)啟動類型,操作系統(tǒng)版本等
漂亮而強大的用戶界面,可以在UI上進行快捷方便的應(yīng)用程序配置
支持約束條件,例如允許一個mesos agent節(jié)點只運行一個應(yīng)用程序
支持健康檢查。可以配置http、https、tcp、command類型的監(jiān)控檢查
完整的RESTAPI,易于集成和編寫腳本。這個對于后期集成來說至關(guān)重要
- # Add the repository
- $ sudo rpm -Uvh http://repos.mesosphere.com/el/7/noarch/RPMS/mesosphere-el-repo-7-2.noarch.rpm
- # Install packages
- $ sudo yum -y install mesos marathon
- # marathon and mesos zk path
- $ cat /etc/default/marathon
- MARATHON_MESOS_USER="root"
- MARATHON_MASTER="zk://192.168.100.9:2181,192.168.100.110:2181,192.168.100.234:2181/mesos"
- MARATHON_ZK="zk://192.168.200.9:1181,192.168.100.110:2181,192.168.100.234:2181/marathon"
- systemctl start marathon
啟動后,直接訪問marathon的8080端口,就能看到一個漂亮強大的UI界面。
我們以springboot應(yīng)用為例,在marathon上創(chuàng)建一個應(yīng)用程序
當(dāng)我們更新應(yīng)用程序時,marathon會新建相同實例數(shù)量的應(yīng)用程序,待healthcheck通過之后替換老節(jié)點,所以不需要擔(dān)心新的服務(wù)沒有啟動期間老的服務(wù)停掉造成線上事故。到這里為止,我們已經(jīng)可以在marathon上方便快捷的進行日常應(yīng)用的創(chuàng)建、升級、擴容、縮容。當(dāng)服務(wù)健康檢查失敗或者機器宕機后,marathon會自動在其它節(jié)點上啟動掛掉的應(yīng)用程序,大大提升了高可用性。
使用nginx upsync/dyups模塊進行平滑變更
當(dāng)我們的微服務(wù)可以隨機分配在不同機器上時,便產(chǎn)生了一個新的令人頭疼的問題。nginx并不知道后端節(jié)點的變更,也不可能每次都去手動修改upstream節(jié)點,reloadnginx,這樣成本就太高了。我們的解決思路是和微服務(wù)的注冊中心打通,當(dāng)服務(wù)注冊、注銷時,都會對注冊中心進行更新,利用nginx upsync/dyups模塊可以動態(tài)修改upstream節(jié)點的能力進行同步,做到平滑變更。如果使用的注冊中心為consul,建議使用upsync模塊,這樣無需開發(fā),只需要簡單的nginx配置,就可以實現(xiàn)我們想要的效果,支持consulkv,consul_services,consul_health,同時upsync也支持etcd。建議使用consul_health接口。upsync模塊不是nginx內(nèi)置模塊,使用時需要重新編譯添加此模塊。
- wget 'http://nginx.org/download/nginx-1.8.0.tar.gz'
- tar -xzvf nginx-1.8.0.tar.gz
- cd nginx-1.8.0/
- ./configure --add-module=/path/to/nginx-upsync-module
- make
- make install
配置文件示例
- http {
- upstream test {
- upsync 127.0.0.1:8500/v1/health/service/test upsync_timeout=6m upsync_interval=500ms upsync_type=consul_health strong_dependency=off;
- upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf;
- include /usr/local/nginx/conf/servers/servers_test.conf;
- }
- upstream bar {
- server 127.0.0.1:8090 weight=1 fail_timeout=10 max_fails=3;
- }
- server {
- listen 8080;
- location = /proxy_test {
- proxy_pass http://test;
- }
- location = /bar {
- proxy_pass http://bar;
- }
- location = /upstream_show {
- upstream_show;
- }
- }
- }
當(dāng)upsync無法滿足我們的需求或者注冊中心不是consul、etcd時,我們可以考慮使用nginxdyups模塊。dyups僅對外提供upstream的增刪查改接口,和注冊中心對比、修改的工作需要我們通過腳本的方式完成。雖然這種方式麻煩一些,但是可定制化程度高,支持http,C,luaAPI,基本上可以滿足大部分的場景需求。
dyups模塊也需要nginx編譯時添加
- $ git clone git://github.com/yzprofile/ngx_http_dyups_module.git
- # to compile as a static module
- $ ./configure --add-module=./ngx_http_dyups_module
- # to compile as a dynamic module
- $ ./configure --add-dynamic-module=./ngx_http_dyups_module
示例配置
- http {
- include conf/upstream.conf;
- server {
- listen 8080;
- location / {
- # The upstream here must be a nginx variable
- proxy_pass http://$dyups_host;
- }
- }
- server {
- listen 8088;
- location / {
- return 200 "8088";
- }
- }
- server {
- listen 8089;
- location / {
- return 200 "8089";
- }
- }
- server {
- listen 8081;
- location / {
- dyups_interface;
- }
- }
- }
特別注意,使用dyups時,proxy_pass時的upstream必須是nginx變量,否則不生效,切記。
整體回顧
經(jīng)過以上調(diào)整,我們得到了以下優(yōu)化
服務(wù)器資源自動分配,合理利用
提升微服務(wù)的高可用性
減低OPS人工成本,更加便于管理和維護