在展开正文之前,我们先分享一下记录片《超级工厂:宜家家居》的故事,宜家作为全球知名的家具领导品牌,在全球几十个国家和地区,拥有数百个商场。宜家的全球化采购和直销模式,能够取得如此巨大的成功,与宜家在创办初期,就确立的标准化设计理念有关。
在宜家,如果一个产品不能被扁平化包装运输,那么即使设计再精妙,也不会被批量生产。设计和运输同样重要!
坚持「可运输性」的设计理念,降低了产品到达终端用户的成本。便宜、快捷的体验,进一步推动着宜家的持续发展。
同样的,规模化的运维,不能再是见招拆招,追着业务满世界跑,应该全局统筹,将多变的业务需求抽象为高度统一的运维模型,通过平台来体系化的支撑。我们希望能有这么一个标准化的魔法箱子,把我们的代码,打包进去,运行、维护、扩容、容灾都是流水线的方式自动化进行。
根据"熵理论"
1.一个孤立的系统,始终会趋向于越来越乱(无序化)的方向发展
2.如果要让一个系统变得更有序,必须有外部能量的输入
所以对于我们动辄几千上万台的互联网行业来讲,加上特有的「快速试错」理念加持,这个庞大的、错综复杂的系统,总是倾向于越来越乱。这就需要我们格外投入精力,才能让系统朝着有序的方向发展。如果我们在设计或者开发阶段,欠下更多的债,埋下更多的坑,那么在产品的运行维护阶段,就要加倍偿还这些技术债务。债总是在那里,只是在哪个阶段还的问题,systems
do not run themselves。
规模化的互联网运维
经常会有人问,1个人支撑10台服务器和1个人支撑2000台服务器,到底哪个更难一些?当运维支撑体系不完善,业务模块都不同构,监控方式、部署方式百花齐放,1个人要支撑10台服务器,就已经疲于应付,处于要崩溃的边缘了;相反,如果所有的服务,都是同样的监控方式、部署方式,同时运维支持体系都是自动化的,那么1个人支撑2000台服务器,也是轻松加愉快的。
以滴滴为例,在四年时间里,从最初只有四台服务器,发展到现在的数万台设备,在这样的发展速度下,显然我们要采用规模化的运作方式,提高运维效率,自动化一切是摆在我们面前唯一的出路。一切系统的设计,都是在满足一定假设前提下的产物,而自动化的前提,恰恰就是“标准化”。
总之,在一个统一的标准和实践引导下,所有人去尽可能靠拢,那么事情会变得简单很多!
所以,半年时间里,我们主要围绕着三个方面在推进服务标准化的事情:
配置管理
常见的配置包括以下一些内容
1.各种开关,比如降级的开关、debug开关、ab测试的开关等
2.各种可配参数,比如超时时间、并发数、日志级别等
3.上下游连接信息
上下游的连接信息,与环境的耦合度最高,是最复杂、最多变、最难处理的部分。我们看看大家一般都是怎么来对付上下游连接信息的。
1.通过LVS来管理,即 vip:port -> real-server-ip:port
列表。这种方案的好处就是充分利用了LVS的高可用特性以及负载均衡、健康检查能力,将上下游的耦合转移到LVS的配置中。这样的坏处也显而易见,配置管理虽然集中化了,但是流量也集中化了,存在严重的单点风险。
2.通过Nginx来管理,即ip:port/server/location
-> upstream列表,该方案的优缺点,同LVS方案,只不过是工作在七层罢了。
3.通过DNS来管理,及domain -> ip列表,该方案负载均衡策略太单一,同时切换速度太慢。
4.通过zookeeper/etcd来管理,这是非常经典的方案,成熟度较高,只不过在网络发生分区的时候容易出问题。
5.通过本地配置文件来管理,这是最原始的方案了,上下游的连接信息,直接写在模块的配置文件中,散落在目标服务器上。使得整个拓扑关系不清晰,故障切换速度慢。
针对这些现实情况,我们迫切需要建设配置管理,来解决:
1.代码(配置)和环境解耦合,用户写好代码,不用再关注测试环境、线上多套集群的差异性,不用关注实例具体跑在哪些资源上。
2.配置集中化管理,使得我们具有自动化拓扑的能力,以及快速切换的能力。
3.支持即时生效、健康检查、负载均衡。
此外,自动注册和发现,这些特性都可以在现有的基础上,方便的叠加。对于运维的系统和基础设施建设,理念的一致性和延续性非常重要,当前的任何一个方案,都要充分考虑和未来三年的长远方向是否一致,今天所做的工作是否在为长远目标铺路,最忌讳的情况就是后来的方案需要不停的推翻早先的方案,业务的改造成本是要重点考虑的。
监控
监控是整个运维环节,乃至整个产品生命周期中最重要的一环,事前及时预警发现故障,事后提供翔实的数据用于追查定位问题,分析业务指标等。
那么残酷的现实情况是怎样的呢?
1.在线日志分析,使用各种正则表达式来提取相关指标
2.这种方案,定制化程度高,维护成本高,试想想,过了三个月,面对你所配置的一大堆正则表达式规则,你有勇气去面对和维护吗?同时在线分析日志,会对在线服务器造成较大的性能消耗。
3.离线日志分析
4.该方案时效性较低,对日志的耦合高,同时大量日志的传输分析需要的资源消耗也是非常可观的,不够经济,不够轻量。
5.实例自身暴露相关status接口
这种方式,理念已经较为先进了,研发在设计和开发模块的时候,就已经充分预见到了需要暴露哪些指标,来有效的监控自身的运行状态和各种统计信息,但是一千个人眼里有一千个哈姆雷特,每位研发同学都有自己的见解,于是这些接口输出格式和意义各不相同,缺乏一致性的规范,在整体运维的层面,造成困难。
6.各种「外挂」形式的监控程序
这种应该是最糟糕、最落后的方式了,研发在设计和开发模块的时候,没有一丝丝的“监控”意识,没有暴露自身的状态和信息,甚至也没有打印相关重要日志,等到这样的代码上线后,才想起来,是不是需要加一些监控。那么对于这些既成事实,受限于业务的压力,运维只能抛却原则和底线,无奈妥协,然后想尽各种旁门左道的办法,给业务模块写监控外挂。这些外挂和每个模块自身特性紧密耦合,业务一不小心改了,监控外挂就得跟着改;同时如果每个业务模块都这么搞,基本上这些业务就处于事实上的“不可运维”状态了。
看完上面的几种情况分析,再一次说明,规模化的运维,不能是见招拆招,应该全局统筹。针对监控,我们提炼了两条基本原则:
1.坚持业务指标采集是代码的一部分原则不动摇,提高指标覆盖率
2.监控方式和指标要标准化,工具支撑系统化
原则1,没有人比模块的研发人员,更清楚其工作机制,更关心其运行状态,模块自身的可运维性就是代码功能的重要组成部分。每次业务逻辑部分的代码变更,都应该伴随着监控指标采集的相应更改。
有了原则1,还远远不够,没有好的工具和体系支撑,提高指标覆盖率就是一句空话。在运维层面,应该制定统一的监控标准,推行统一的最佳实践,提供统一强大便捷的metrics
lib库支撑。这样才能更容易的推进自动化进程,以及更高的监控指标覆盖度。
谈谈监控标准化,标准如何定义?
1.每个业务的每个接口,都要可被监控
2.每个接口的监控指标,必须至少包含:
cps
latency-50th/75th/95th/99th...
error_rate
error_count
3.可以在2的基础上,扩充相关自定义指标,比如:
caller
callee
这样就可以细化到调用关系级别的数据
4.所有的指标上报,采用主动push机制,无需预先注册
有了上面的一些标准化的指导思想,我们就可以着手开发lib库,推进业务模块接入了。以nginx为例,监控指标采集,可以参考我们的实现http://book.open-falcon.org/zh/usage/ngx_metric.html
,采集到的指标包括:
nginx指标标准化
1.api tag: 即nginx request uri,各统计项按照uri区分。当api为保留字__serv__时,代表nginx所有请求的综合统计
2.error_count、upstream统计项根据实际情况,如果没有则不会输出
有了这些标准化的指标,很少的几个告警策略就能覆盖到绝大数的业务模块,而不用担心针对每个业务添加不同的告警策略。同时可以针对每个业务,根据不同的用户,建立各自的dashboard,比如针对老板、研发、运维、测试,关注的dashboard侧重点都有所不同。
每个服务都要有自己的大盘
大盘可能长这样
大盘也可能长这样
部署
说起来很简单,部署就是将代码、配置、数据,在一组资源上,保持给定数量的实例在运行。
但,现实是骨感的,存在着这样那样的痛点:
1.新业务接入沟通成本高
2.环境依赖多(PHP/java/golang/c++)
3.上下游连接信息管理乱(拓扑不明确,散落在各个目标服务器上)
4.用户体验不统一(编译打包、发单、审核、执行、观察各个环节脱节)
5.增量更新存在协同上的问题
部署和变更,我们的一些原则:
1.以版本为发布单位
2.统一的接入流程和打包规范(也可以很方便的构建为docker image)
3.集中化的配置管理,配置与线上环境解耦
4.统一的上线流程和检查机制(preview、小流量、集成监控告警、集成趋势图)
5.日志依赖解耦(网络日志)
可以预见,经过坚持不懈的标准化改造,线上服务:
1.配置和环境解耦了
2.监控标准化了
3.部署规范化了
4.日志网络化了
5.数据service化了
6.实例自发现了
7.资源容器化了
8.全自动化调度,顺势而为罢了。
|