本文来自EGO技术管理公开课上,才云科技创始人兼CEO张鑫的线上分享。张鑫,博士毕业于美国卡内基梅隆大学,曾为美国谷歌软件工程师、技术带头人,多年从事谷歌核心技术底层系统研发。主要参与研发了基于新一代容器集群技术(Borg)的谷歌私有云系统,自动化管理谷歌近百个数据中心中的上百万台服务器和每周20亿个容器化应用等项目,是分布式系统与网络安全领域的学术专家。
他于2015年回国创办才云科技有限公司,将谷歌级容器集群管理平台和自动化开发运维经验以PaaS产品和服务的形式提供给国内企业,现已落地国内诸多行业龙头企业,极大地为其提升了系统稳定性和效率并显著节省了IT成本。
如何更好地进行技术工程管理?
大家好,我是才云科技的创始人兼CEO张鑫,曾参与谷歌私有云管理平台和公有云产品的建设,今天跟大家分享一下谷歌内部项目人员管理和开发运维一体化的实践经验。
技术项目管理
技术项目管理的宏观理论很多,而我在本次分享中以我在谷歌从事软件开发和技术项目管理的角度,介绍一下我们采用的一些具体的、细化的实践方法和工具。由于Google内部系统庞大,不同的团队在不同的时间会采取不同的方案,我这里只列举一些常用的方法实践:
1、OKR的制定
OKR是指Objectives and Key Results,与KPI(Key Performance Indicator)相比,OKR更融入了战略性的目标和计划的成分。顾名思义,OKR的制定分为两个部分:Objectives和Key Results。一个简单的OKR例子:
Objective: 实现向新一代容器管理平台的迁移
OKR的制定是分层级的, 首先公司会制定一个公司级别的战略OKR,然后围绕着这个目标,各个PA(Product Area)、一直到各个行政组、一直到个人都会制定更细化的OKR。一般OKR是按照每个季度制定一次,而公司层面通常会有更长远的年度OKR。
2、OKR的审核
在每个季度结束时我们会审核OKR并给OKR做打分,由于OKR在制定之初是从公司到团队到个人,在审核时我们同样查看在不同层面、不同领域、不同团队的完成情况。并在各个层面打出0到1的一个分数(1表示完全完成,0则表示没有开展任何工作)。
在打分时,我们十分强调功能上线并经过验证;仅仅是代码开发好但并未上线经过验证的功能/任务,得分不会超过0.6。OKR的打分会影响到产品、团队的绩效和个人的performance review,我们也会将当前季度的OKR与以往季度的OKR进行对比来分析走势。
一个有意思的问题是Google认为最理想的OKR平均得分是多少,答案并不是1,而是0.7。我们在制定OKR的时候,强调要有stretch goal,要be aggressive,所以大家很难把所有的目标都实现,而留有未完成的空间则会充分激励大家尽量去缩小和“1”的差距。事实上,Google整个公司的OKR是0.67左右。
3、技术进度的把控
Google内不少团队采用三层规划的方式来把控项目进度:
季度OKR层面:如上所述,每个季度根据OKR结果来跟踪进度。
Sprint层面:一个季度内制定多次的Sprint(冲刺),一般与每次发布对其,周期为1周到几周不等。
每周的层面:每周的技术Sync保证当前的Sprint进展顺利。
每天的层面:有的团队会每天(或隔天)进行比较敏捷的“standup”,小组内大家站在一起,各自用简短的语言汇报工作并确保“路障”能被及时清除。有意思的是,为了确保这个standup简短有效,有的团队要求大家在发言期间采取“Wall Sit”的姿势(一般人Wall Sit一分钟就会比较吃力),迫使大家或者简洁或者好好锻炼身体。
除了外界熟悉的Scrum, Pivotal Tracker等敏捷开发管理方法和工具以外, 不少Google内部技术开发团队会采取一种planning poker的模式来对任务进行把控,具体流程如下:
首先,在每一个Sprint周期伊始,我们按照优先级把该Sprint内所需完成的任务列表列出来,并赋予优先级排序。
其次,我们拿几个写有斐波那契数字的牌:1, 2, 3, 5, 8, 13,其中数字代表一个任务的工作量的权重。
对于上述任务列表,团队中的每个成员独立打出一个牌来代表自己对于该任务的任务量评估。对于一个任务,当大家给出的分数不同时,会有给出最低分的人和给出分数最高分的人来辩论,而且大家进行二次投票。
一旦任务的权重被分配,我们会将会记录每个Sprint周期内团队所能完成的点数。几个Sprint以后,我们就会有一个不错的对于团队效率的计算(例如一个Sprint平均能完成80个点),便于后面的任务安排和规划。
4、SRE, Interrupts与release shepherd
谷歌内部非常注重开发与运维的分离;对于传统的运维我们定义为手动的、重复性的、没有长久附加价值的人工劳动。因为,谷歌内部鼓励通过Devops的方法逐渐减少传统运维的成分。
例如谷歌内部采用自动化的集群管理平台(基于容器技术和容器集群管理平台Borg等工具),使得一名运维人员(与传统运维人员不同,谷歌内部称之为Site Reliability Engineering)平均可以管理上万台服务器。谷歌具体的开发与运维分离方法包含两种:
将开发者(SWE:Software Engineer)与运维者(或者谷歌特色的SRE: Site Reliability Engineer)分岗,SRE转岗负责更多的平台级别的维护。同时,即使在SRE岗位内部,谷歌也严格控制每名SRE所参与的手动运维时间,尽量将其控制在50%一下,保证SRE能有一半的时间投身于自动化运维工具、系统、平台的研发。当然,SRE也有oncall,当接收到紧急任务时(被传呼),当值的SRE需要在10多分钟内到达键盘前做出响应。
在开发者中也不可避免的从事一些运维或者处理应用突发事件的时候。例如当某个线上服务出现问题时,SRE往往会找到对应的开发团队协助调查原因并提交修复补丁。为了减少此类突发事件对于开发人员的研发任务影响,不少开发团队采用interrupts轮岗制:在每一个产品版本发布周期内,轮流由一名开发者来担当interrupts角色,并与SRE团队协调,成为SRE的point of contact,负责处理外来interruption和bug的初步诊断(triage)。
此外,谷歌的产品新版本上线有着严格的QA和测试流程,除了和大家所熟悉的开发、测试、生产环境的搭配使用以外,想突出两个特点:
谷歌的产品测试不依赖于专门的测试工程师,而是要求软件作者自己要去进行一系列的单元、整合测试,以及在测试环境的测试等。软件作者在极大程度上是自己代码的负责人。
在新版本的发布过程中,我们深度采用了不同形式的灰度测试机制。例如如果是平台软件更新(例如容器集群平台,服务器基础镜像升级),是按照一定的速度逐渐更新到不同的数据中心。
例如第一天发布到一个数据中心,第二天发布到5个数据中心,以此类推,并在过程中不断进行A/B测试和对比。如果是面向用户的产品(例如广告、购物等),则会采用基于用户流量分流的灰度发布法,例如先选择5%的用户流量使用新的版本,并自动收集metrics来进行新、旧版本的比对。
技术人员机制管理
下面我简单举几个有意思、有特色的内部人员管理机制实践。
1、performance review
谷歌的绩效考评被称为Performance Review,通常是每个季度或半年进行一次。其中很大的亮点就是该考评主要依赖于同事之间互评(peer review),同事的级别越高,review越有份量。这样的初衷是避免将员工的绩效打分大权完全交给顶级上司,同时也为了促进健康的同事间关系和积极的互帮互助。
Performance review分为below expectation, meets expectation, exceeds expectation, strongly exceeds expectation和superb几挡,其中每次performance review达到 meets expecation以上的有近40%左右。
2、team rotation
为了保证技术人员的创新活力,谷歌内部鼓励一定程度的项目轮换。一般在同一个产品线或团队中待满一年并且绩效考评达到要求后,可以自由的换岗。寻找新的产品团队时既可以通过谷歌内部的招聘大会和招聘平台,也可以通过口口相传。
3、20% time
谷歌一直以来有一个20%的传统,就是允许每一个工程师拿出20%的时间去做一些对公司长期发展有利的“副业”,包括学习新技能,参加培训课程,参加学术研究,做有意思的新产品等。这个制度的初衷是保持员工的技术积极性,同时保持谷歌的创业创新文化,例如Gmail就是从20%项目发展而来的。然而今年随着20%项目在Performance Review中受重视程度降低,导致20%项目有些名存实亡。
谷歌Devops实践分享
时间关系,这次分享中我仅介绍一些高层的Devops理念。首先,软件工程的过程就像生一个小孩,而维护这个出生后的软件往往在谷歌内部要花费40%到90%的精力。传统的运维存在诸多问题,例如较高的人力成本,对运维人员的长期职业发展不利,以及造成开发团队和运维团队之间的利益冲突。
而谷歌内部的Devops实践被称为Site Reliabiliy Engineering,是希望将大部分的人工运维时间转化为开发自动化运维工具的时间,从而从长远来讲实现更高程度的自动化系统管理。而SRE的最重要的目标就是稳定性。
SRE体现了如下的核心智慧:
一定要专注于持久的运维工具开发,将人工操作降到50%的时间以下。
采用error budget(错误预算)的方式来缓解开发团队与SRE团队(或运维团队)之间的利益冲突:开发团队希望新的版本迭代越快越好,而运维团队希望系统越稳定越不变越好。
在设定SLO的时候,不应该力求100%的稳定性,而是根据系统所有环节,制定N个9。
系统一定要有稳健的监测系统,四个黄金监测对象包括:延迟、流量、错误率和资源饱和率。
系统中的70%的问题都是由于配置改变所导致的,所以配置管理是核心要素。
敏捷的持续集成和持续发布系统是必须,包括构建、切分支、测试、打包几个部分。
采用容器技术和自动化容器集群管理技术是实现高可用、高效能系统的秘密武器。
揭秘谷歌每周20亿+容器背后的管理技术
接下来,我给大家分享一下谷歌使用容器集群技术的案例实践,由于我个人在集群管理团队从事了3年的研发,这里带来的是我个人的经验和观点。
首先大家应该都听说过容器是什么,而Docker则是基于容器技术的现阶段最流行的一种容器产品、工具和生态。对于不了解Docker或者容器的人,一个简单的比喻(但不是最贴切)就是容器就是一个更轻量级的“虚拟化”和“应用隔离”工具。具体有多轻量呢?
一个服务器可能可以运行10个虚拟机,但是一个服务器上可以运行上百个容器,不同容器里运行用户的应用,并在一定程度上实现了相互之间的隔离。此外,容器可以在秒级启动,相比于启动一个完整的虚拟机也有巨大的优势。除了效能上的提升,容器还是一种应用的打包格式,可以将应用和它运行时的依赖封装在一起,实现一次封装、处处运行的功能。
谷歌从2000年初开始使用容器,但是它所使用的是自研的一种叫做lmctfy的容器格式,其实是Let Me Contain That For You几个单词首字母的缩写。谷歌最早使用容器的初衷之一是节省物理资源,通过用容器取代虚拟化层(hypervisor和每个虚拟机所占用的物理资源)来极大地节省计算成本。
谷歌在2013年对lmctfy其进行了开源https://github.com/google/lmctfy,但由于流行程度不如Docker,后面就没有再继续推广。同时,根据谷歌内部运行15年容器的经验来看,将应用程序装入容器仅仅是第一步,而后面的大量工作是如何管理、运维这一个全新的容器世界,因此谷歌在2014年将精力转入了开源容器集群管理技术,即Kubernetes项目:https://github.com/kubernetes/kubernetes
下面我们正好来聊聊谷歌容器集群的实践。谷歌在2015年已经达到了80多个数据中心,超过一百万台机器。其中大家所熟知的search,youtube,maps,gmail等所有产品,包括很多我们使用的内部工具,都是基于容器在运行。这个容器的数量是巨大的,官方称之为每周运行20亿个容器。那么紧接着我们面临的问题就是如何去管理这么多的容器,其包括:
决定哪个容器运行在哪台服务器上
如何实现应用容器的多副本部署来实现高可用、高并发,同时按需动态伸缩以节省、优化资源利用率
如何自动监测应用的运行状况,并在出错误时进行自我修复和故障转移
如何实现应用于配置的解耦合,使得一个数据中心的业务系统可以快速的“全盘”复制到另外的数据中心里(我们称之为cluster turnup and turndown,基本上是每个季度都会发生的事情)
谷歌为此建立了一整套集群管理(Cluster Management)机制,其中包含几十种不同的组建。如下图所示:
其中在外界知名度最高的容器任务管理组件:Borg。它之所以在外界更为人所熟知,一方面是由于谷歌发表了关于Borg的论文:《Large-scale cluster management at Google with Borg》, 另一方面也由于谷歌基于Borg的思想和实践开源了Kubenretes项目。
Borg的最主要功能是一个容器任务调度和编排系统,负责将容器化应用自动地运行在何时的主机上,并对容器应用的生命周期(生老病死)进行自动化优化管理。下面我通过一个案例来描述一下这一整套集群管理系统的实践流程。我们以建立一个新的数据中心并在其上运行一套广告业务为例来看看谷歌的一整套运维、开发、管理流程。
1、初始化
我们从硬件开始说起。当一台服务器从QA通过后,它会投放到数据中心里的一个合适的rack中。当硬件设施、网络都配好后,该服务器的信息会被写入一个集中的机器数据库里。这个数据库里不光记录了机器的硬件配置信息,还会记录这台服务器会被赋予哪些平台级别的特殊使命(例如运行Borg的master节点、运行Chubby服务器等)。默认地,每一个服务器上都要运行Borg的工作节点服务(Borglet),用来运行用户应用和业务。
随后,在集群管理系统里一个叫做“亚里士多德”的组件会定期(每15分钟)获取机器数据库中的最新数据,当发现有新的服务器时,则会按照指示对该服务器进行配置:
a) 先通过调用一个叫做installer的组件对机器进行操作系统的安装(谷歌叫做Prodimage,是一个基于Ubuntu的经过安全改良的系统镜像)
b) 然后根据数据库中的指示,在服务器上安装合适的平台软件(borglet,borgmaster,chubby等)。
这里指的点出的是,我们对于每一个生产服务器的配置和安装,并非是通过ssh进行,而是通过在机器上安装一个API服务(称为sushiD),并通过调用API进行。这样可以避免SSH所暴露出来的过多的权限和潜在的attack surface。这个流程我用图表总结如下:
2、管理和监测系统平台
当服务器和平台服务都运行起来以后,集群管理系统则处于一个有限状态机的模式,对服务器和上面的平台软件(例如Borg,Chubby等)进行不间断、自动化的管理和维护。
每个机器上安装的一个“机器医生”agent会时刻关注服务器状态(例如通过观测/proc目录等),并根据自己的一个“症状规则库”判断机器是否出现问题,例如 bad-hda, slow-ethernet等,如有,则将此问题加入机器数据库中。
亚里士多德系统在定期检查机器数据库时会发现服务器上的问题,并采用相应的workflow和工具进行软件修复。在谷歌,有60%的“硬盘”或文件系统故障都可以通过此自动化在线修复工具完成修复,无需人工介入。
除了对机器的管理,亚里士多德还会通过预先定义的server 模块和健康检查机制检查平台软件的健康性(例如Borg等)。无论是出现软件问题,还是软件所在的机器出现了问题,根据策略我们会采取不同的修复手段和软件迁移机制。
例如如果是Borg的master所在的物理服务器出现硬件问题,哪怕这个问题还没有影响到上面的服务(例如机器过热),亚里士多德会触发在线替换的workflow,主动在新的机器上部署Borg Master服务,做到未雨绸缪。
当修复机器问题时,我们要做的一个准备工作叫做drain,就是把机器上的业务和数据先删除掉(由于谷歌内部的应用、数据都采用分布式结构,使得删除某个节点不会影响整体业务)。然而在删除前,亚里士多德系统会询问一些安全把控组件,保证该服务器下线后不会影响整体的系统容量。
上述是一个非常基本的工作流,只是管中窥豹。我用流程图总结如下:
3、发布并运行应用
谷歌的代码都存放在同一个庞大的代码库中,开发者在开发完代码后类似于Github里的Pull Request一样也要发一个Change List,进行code review。在谷歌,code review是严格执行的,否则代码无法提交(除了特殊情况)。大致的开发流程如下:
开发者写好代码后,先在本地进行编译。由于谷歌的代码库非常庞大,编译代码所需的依赖可能就需要很长时间。谷歌内部使用了一个叫做blaze的编译和测试工具,Blaze可以运行在Borg容器集群上,通过优化的依赖分析,高级的缓存机制,和并行的构建方法,可以快速地对代码进行构建。而谷歌也将这一工具进行开源:http://www.bazel.io/
构建完成后,我们需要在本地进行单元测试,而单元测试的运行测试由一个内部叫做Forge的系统完成,而Forge也是通过运行在Borg容器集群上从而实现快速的并行测试。
当本地的代码更新以Change List的形式发送出来以后,谷歌内部的人员通过一个叫做Critique的UI进行代码审查,同时Change List会触发一个叫做TAP(Tap Anything Protocol)的系统对该Change List进行单元测试,并保证这个局部的代码变化不会影响谷歌的其他应用和代码。TAP具有智能的依赖监测功能,会在谷歌内部浩瀚的代码库和产品线中检测到哪些部分可能会被潜在的影响到。
当代码通过测试和审核提交后,我们会等到下一个release cycle进行发布。如前所述,谷歌内部的应用都是以容器的形式运行在Borg上。因此发布的第一步工作就是通过一个叫做Rapid的系统,对代码进行容器打包成镜像(内部称为MPM格式),再通过Rapid发布工具进行发布(按照前述的灰度发布原则)。
用流程图总结如下:
4、应用运行期间的自动化管理
最后,我来简单分享下谷歌是如何采用容器集群Borg来实现其应用的高可用和高扩展性的。由于Borg博大精深,我这里只列举一些经典的功能:
1)动态任务调度:开发者通过Borg的命令行来将应用跑起来。在一个Borg Cell里,Borg调度器将会动态的、自动的、智能的为不同的应用选择合适的机器来运行。
如大数据业务、cron job、Google web业务、搜索业务等应用都会被动态的分配到集群中的不同主机上,调度算法会根据每个主机当前的物理资源情况来做优化,实现物理资源利用率最大化,并保证各个主机的流量平均分配,不会造成局部热点。不同的任务有不同的优先级,来保证大数据任务不会在用户流量高峰期抢占web业务的资源。
2)模块、服务间的自动服务发现:Borg内运行的所有应用都有一个类似于DNS的名称,我们内部称之为BNS Path。不同的服务间相互访问时可以直接根据BNS名称来进行连接,BNS系统会自动地将名称转化为实际的IP地址。
因此,在不同的环境切换时(例如从测试到生产)、或随着主机的重启或更换而导致底层IP地址变化,应用程序也无需做任何修改就可做到无缝迁移,极大地减少了环境配置和人工操作来带的成本与风险。此外,BNS的方式也更好地支持了应用的多实例部署,在具体的实例发生变化时,应用的BNS不变。
3)多副本负载均衡与弹性伸缩:为了应对互联网应用的突发和难以预测的用户流量,用户在Borg平台部署应用时可指定所需要的副本数量,例如运行10个Nginx的实例。Borg会自动创建指定个数的应用实例,并且:
a) 对应用进行实时监测,保证任何时候都有指定数量的实例在运行。如果由于主机故障导致2个Nginx实例失效,Borg会主动地创建2个新的Nginx实例来保证高可用。
b) 当其他服务需要访问Nginx时,无需直接绑定具体10个实例中的任何一个IP地址,而是可以通过上述的服务名称(例如“Nginx”)来访问。Borg会自动将请求按照一定的负载均衡策略转发到10个实例中的合适实例。
c) 集群管理中的其他组件如 Autoscaler还支持自动伸缩策略,例如当CPU利用率超过60%时,自动将Nginx从10个实例扩展到20个实例。
4)自我修复与故障应对:当应用程序出现故障时,Borg会自动发现并在新的主机上重启应用。Borg检测故障的方法可以针对业务和应用进行定制化,除了简单地检测应用是否在运行以外,还支持基于HTTP钩子的自定义监测(内部称为healthz和varz)。而其开源的Kubernetes也支持类似的自定义健康检查规则:
a) HTTP钩子:例如对于Web应用,检测其服务URL是否正常
b) 检测脚本:对于任意应用,通过定时在应用容器中运行自定义脚本进行检测。以Redis为例,可以通过 “redis-cli”来进行自定义的数据检查。
c) TCP socket:可以通过检测TCP socket来判断应用是否健康。
5)配置管理:一个复杂的生产系统中存在诸多配置,除了不同组件的IP地址、端口,还有应用程序的配置文件、中间件的配置文件等。Borg充分利用了基于Chubby的配置管理服务,实现应用与配置的分离。
用户可以将不同环境下的应用配置文件、数据库密码、环境变量等配置放入每个集群内统一的Chubby服务中,并为每一个配置项取名字(例如 “APP_CONFIG_FILE”, “DB_PASSWORD”等),而后应用可通过这些名字来在运行时获取这些与环境相关的配置信息。
此外,Chubby支持watcher功能,因此应用程序可以动态监听其配置文件是否有变化,实现配置的热更新。感兴趣的朋友可以参考Chubby的论文来了解更多详情:http://research.google.com/archive/chubby.html
▽
本文来自EGO技术管理公开课,技术管理公开课参与方式:关注EGO公众号(EGONetworks),后台回复“公开课”,经审核加入EGO技术管理公开课群。
喜欢我们的会点赞,爱我们的会分享!