隨着近幾年微服務與雲計算的飛速發展,機器由物理機逐步變爲了虛擬機,應用服務由龐大的單體應用逐漸變爲了若干個微服務聯合組成的應用集羣,更新迭代的速度成倍上漲,傳統的部署模式已沒法知足開發平常更新需求,須要一套適合微服務的管理架構。nginx
技術棧及文檔git
資源調度框架 MESOSgithub
應用編排平臺 Marathonspring
nginx 動態修改 upstream dyupsdocker
nginx 動態修改 upstream upsyncapache
使用Mesos 進行機器資源管理後端
首先,是機器資源的管理。在微服務的架構中,原有的單體服務被拆分紅了一個個獨立單元的應用程序,這些服務體量較小,能夠獨立運行在配置較小的機器上。爲了故障隔離,咱們會盡量的把這些服務部署在不一樣的虛擬機上,這樣機器的數量會成倍增長。對於運維來講,每一個新服務部署時,須要先查看現有機器的剩餘資源是否知足新服務的需求,有時可能由於評估不許確形成來回擴容、遷移,或者資源浪費。springboot
開始時,咱們的架構可能時這樣的服務器
爲了解決上面的問題,可使用 MESOS ( 布式資源管理框架),它能夠 讓咱們像用一臺電腦(一個資源池)同樣使用整個數據中心。
mesos 部署時分爲 master 和 agent 兩個角色,固然,你能夠在同一臺機器啓動它們。架構
安裝Mesos 前須要安裝zookeeper,mesos 使用zk 實現高可用和選舉,包括一個 master leader 和 幾個備份 master 避免宕機。
Mesos master 負責管理各個Framework和Slave,並將Slave上的資源非配給各個Framework。
Mesos agent 負責管理本節點上的各個Mesos Task,爲各個Executor分配資源 (低版本爲 mesos-slave)。
$ cat > /tmp/bintray-mesos-el.repo <<EOF
[bintray-mesos-el]
name=bintray-mesos-el
baseurl=https://dl.bintray.com/apache...
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 # 容器類型,默認 mesos,能夠添加 docker,如: mesos,docker
|-- hostname
|-- ip
|-- log_dir
|-- master # master 地址,格式爲 host:port 或
zk://host1:port1,host2:port2,.../path 或 file:///path/to/file
|-- resources # 設置總資源大小,能夠設置小些來預留更多機器資源
`-- work_dir
$ cat /etc/mesos/zk # 設置 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
當mesos服務啓動後,agent 會向master 節點彙報機器資源,包括CPU、內存、磁盤等。 當咱們要發佈一個服務時,只須要設置這個服務的CPU、內存、磁盤參數, mesos master 會自動幫咱們選擇有足夠資源的機器去運行,以下圖
咱們將微服務的啓動都交給 Mesos 管理,這樣咱們只須要關注總體資源便可。MESOS 提 供了UI界面,能夠直接訪問 mesos master 的5050 端口,查看集羣資源使用狀況。 整體使用狀況 及 Agent 節點使用狀況
完成以上後,咱們的架構變成了這樣
使用Marathon 進行微服務管理
Marathon 是創建在 Mesos 上的私有 PaaS平臺。它能自動處理硬件或者軟件故障,並確 保每一個應用程序都"永遠在線"。 咱們使用 Marathon 管理微服務有如下優點 1. 支持容器和非容器,不受限於服務啓動類型,操做系統版本等。 2. 漂亮而強大的用戶界面,能夠在UI 上進行快捷方便的應用程序配置 3. 支持約束條件,例如容許一個mesos agent 節點只運行一個應用程序。 4. 支持健康檢查。能夠配置 http、https、tcp、command 類型的監控檢查。 5. 完整的REST API,易於集成和編寫腳本。這個對於後期集成來講相當重要。
$ sudo rpm -Uvh http://repos.mesosphere.com/e...
$ sudo yum -y install mesos marathon
$ 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 應用爲例,在 marathon 上建立一個應用程序
當咱們更新應用程序時, marathon 會新建相同實例數量的應用程序,待 health check 經過以後替換老節點,因此不須要擔憂新的服務沒有啓動期間老的服務停掉形成線上事 故。 到這裏爲止,咱們已經能夠在marathon 上方便快捷的進行平常應用的建立、升級、擴 容、縮容。當服務健康檢查失敗或者機器宕機後,marathon 會自動在其它節點上啓動掛掉的應用程序,大大提高了高可用性。
使用 nginx upsync/dyups 模塊進行平滑變動
當咱們的微服務能夠隨機分配在不一樣機器上時,便產生了一個新的使人頭疼的問題。 nginx 並不知道後端節點的變動, 也不可能每次都去手動修改 upstream 節點, reload nginx,這樣成本就過高了。 咱們的解決思路是和微服務的註冊中心打通,當服務註冊、註銷時,都會對註冊中心進行 更新,利用 nginx upsync/dyups 模塊 能夠動態修改 upstream 節點的能力進行同步,作 到平滑變動。 若是使用的註冊中心爲 consul,建議使用 upsync 模塊,這樣無需開發,只須要簡單的 nginx 配置,就能夠實現咱們想要的效果, 支持 consul kv, consul_services, consul_health, 同時 upsync 也支持 etcd。建議使用 consul_health 接口。 upsync 模塊不是nginx 內置模塊,使用時須要從新編譯添加此模塊。
wget 'http://nginx.org/download/ngi...'
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;
}
}
}
當upsync沒法知足咱們的需求或者註冊中心不是 consul、etcd 時,咱們能夠考慮使用 nginx dyups 模塊。dyups 僅對外提供 upstream 的增刪查改接口,和註冊中心對比、修 改的工做須要咱們經過腳本的方式完成。雖然這種方式麻煩一些,可是可定製化程度高, 支持 http, C,lua API,基本上能夠知足大部分的場景需求。
dyups 模塊也須要nginx 編譯時添加
$ git clone git://github.com/yzprofile/ngx_http_dyups_module.git
$ ./configure --add-module=./ngx_http_dyups_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 變量,不然不生 效,切記。
總體回顧
通過以上調整,咱們獲得瞭如下優化