随着近几年微服务与云计算的飞速发展,机器由物理机逐步变为了虚拟机,应用服务由庞大的单体应用逐渐变为了若干个微服务联合组成的应用集群,更新迭代的速度成倍上涨,传统的部署模式已无法满足开发日常更新需求,需要一套适合微服务的管理架构。
技术栈及文档
资源调度框架MESOS
应用编排平台Marathon
nginx动态修改upstream dyups
nginx动态修改upstream upsync
使用Mesos进行机器资源管理
首先,是机器资源的管理。在微服务的架构中,原有的单体服务被拆分成了一个个独立单元的应用程序,这些服务体量较小,可以独立运行在配置较小的机器上。为了故障隔离,我们会尽可能的把这些服务部署在不同的虚拟机上,这样机器的数量会成倍增加。对于运维来说,每个新服务部署时,需要先查看现有机器的剩余资源是否满足新服务的需求,有时可能因为评估不准确造成来回扩容、迁移,或者资源浪费。
开始时,我们的架构可能时这样的
为了解决上面的问题,可以使用MESOS(布式资源管理框架),它可以让我们像用一台电脑(一个资源池)一样使用整个数据中心。
mesos部署时分为master和agent两个角色,当然,你可以在同一台机器启动它们。
安装Mesos前需要安装zookeeper,mesos使用zk实现高可用和选举,包括一个masterleader和几个备份master避免宕机。
Mesos master负责管理各个Framework和Slave,并将Slave上的资源非配给各个Framework。
Mesos agent负责管理本节点上的各个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 # 容器类型,默认 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、内存、磁盘参数,mesosmaster会自动帮我们选择有足够资源的机器去运行,如下图
我们将微服务的启动都交给Mesos管理,这样我们只需要关注整体资源即可。MESOS提供了UI界面,可以直接访问mesosmaster的5050端口,查看集群资源使用情况。总体使用情况及Agent节点使用情况
完成以上后,我们的架构变成了这样
使用Marathon进行微服务管理
Marathon是建立在Mesos上的私有PaaS平台。它能自动处理硬件或者软件故障,并确保每个应用程序都永远在线。我们使用Marathon管理微服务有以下优势
支持容器和非容器,不受限于服务启动类型,操作系统版本等
漂亮而强大的用户界面,可以在UI上进行快捷方便的应用程序配置
支持约束条件,例如允许一个mesos agent节点只运行一个应用程序
支持健康检查。可以配置http、https、tcp、command类型的监控检查
完整的RESTAPI,易于集成和编写脚本。这个对于后期集成来说至关重要
- # 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应用为例,在marathon上创建一个应用程序
当我们更新应用程序时,marathon会新建相同实例数量的应用程序,待healthcheck通过之后替换老节点,所以不需要担心新的服务没有启动期间老的服务停掉造成线上事故。到这里为止,我们已经可以在marathon上方便快捷的进行日常应用的创建、升级、扩容、缩容。当服务健康检查失败或者机器宕机后,marathon会自动在其它节点上启动挂掉的应用程序,大大提升了高可用性。
使用nginx upsync/dyups模块进行平滑变更
当我们的微服务可以随机分配在不同机器上时,便产生了一个新的令人头疼的问题。nginx并不知道后端节点的变更,也不可能每次都去手动修改upstream节点,reloadnginx,这样成本就太高了。我们的解决思路是和微服务的注册中心打通,当服务注册、注销时,都会对注册中心进行更新,利用nginx upsync/dyups模块可以动态修改upstream节点的能力进行同步,做到平滑变更。如果使用的注册中心为consul,建议使用upsync模块,这样无需开发,只需要简单的nginx配置,就可以实现我们想要的效果,支持consulkv,consul_services,consul_health,同时upsync也支持etcd。建议使用consul_health接口。upsync模块不是nginx内置模块,使用时需要重新编译添加此模块。
- 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;
- }
- }
- }
当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变量,否则不生效,切记。
整体回顾
经过以上调整,我们得到了以下优化
服务器资源自动分配,合理利用
提升微服务的高可用性
减低OPS人工成本,更加便于管理和维护