为什么我认为架构师需要坚持写代码?

最近在高可用架构群、EGO会员群等多个场合,大家都在讨论架构师的能力的问题,架构师应该具备哪些能力?在面试时如何合适的评估一个架构师的能力?

架构师的两种类型

第一种是可以将业务实现的人,他可能需要整合公司不同部门的资源、解决不同技术模块整合、解决不同版本之间的兼容性、解决各个模块的技术选型等,解决任务的分解及分配,解决进度上出现的问题。当上面所有这些问题都完成后,架构师顺利帮助公司完成了项目目标。

第二种是在第一种的基础上,利用技术的力量,改进了一个领域的效率或提升了生产力。比如一个在现有技术基础上提升20%效率的视频解码模块、或者类似美剧硅谷中的,研发出一套压缩比很大且保持高质量信息的压缩算法。目前的大部分互联网创新在某种程度也是利用技术变革的力量,比如电子商务及在线教育等行业。

如果从输出结果的角度来看,架构师有两种类型,具备技术杠杆能力的和不具备杠杆能力的架构师。并不否认第一种架构师在战略执行层面的作用,他们是各个软件开发团队的中坚力量。但从影响力的角度,其归根结底是在一个画好的表格里面填东西,他从事领域的最终的格局是由市场、运营或者产品主导。而一种是真正具备杠杆能力的工程师或者架构师,他可以利用技术的力量,在填写一个格子的同时,利用技术的力量,将格子的功效放大,影响十倍或者百倍以上的结果。比如在音乐播放软件中,推荐算法的应用彻底改变了用户播放音乐的习惯与体验。

很多人所说的架构师的设计能力,大多也可以归纳到第一种情况。很多所谓的架构设计,就是拿着多年一成不变的分层模式往业务上套,把业务按照功能规划成软件模块填写到架构图,并且把上下游的调用串起来。这种设计的大多时候是起给客户或者领导展示的作用。程序员代码的整体构思,大多可以通过白板上或者白纸以及程序员直接的沟通很敏捷的完成,大多不需要一个专职画图纸的架构师来指导。

第一种架构师是可以不写代码的,因为他大部分所做的事情是跟人打交道、分配任务以及解决开发过程中各种进度问题。因此很多技术负责人面试时候看重协调能力等非真正的技术能力。而那些服务甲方项目型的公司,更是特别看重人际关系、沟通能力、展示能力等跟客户打交道的能力。另外一些软件版本历史包袱重的企业,则看重架构师的打补丁能力。由于功能型及偏执型型的团队偏多,因此在很大程度上造成了架构师的能力标准的偏离,在一些讨论的场合,过份看重项目执行中的个别技巧型能力,比如项目管理、人际关系等能力常常还占据了主流的声音。

但这类架构师只能勉强称为“技术架构师”,因为大部分时候,他做的事情是填格子,而无法做到利用技术的力量,把一个格子放大到10个格子及更多。在另外一方面,这些不写代码进而慢慢丧失代码能力的“架构师”,也不太可能利用技术的力量去做发挥技术杠杆的事情。当然技术架构师也可以驱动工程师去完成一个技术型的大项目,大型的项目也需要合理的组织,但并不意味不写代码的人就比写代码的人做得更好。而那些对技术体系有深入了解及一线体验的架构师,比那些只跟人员管理打交道的人,更有机会利用技术的力量促进变革。

因此如果希望一个架构师有令人满意的技术驱动能力,他应该具备代码能力,对技术有直接的了解及体验,进而能够精通如何利用技术来改变未来生产力。

如何面试及评估架构师的能力

Tim 的面试方法是,候选人需要第一步通过电脑上完成一个小型的代码实现,在代码基本符合要求的情况下,才会获得所有面试官可以接受的一个能力起点。如果不做这一点,面试时候,面试官需要费尽心思去问对方项目上更多细节问题,才可能了解一个候选人真正的开发能力。而通过考试,则可以在验证候选人具备一定开发能力的基础上,愉快的聊一些其他轻松的话题。

在EGO会员讨论时候,一部分创业公司技术负责人担心一些资深的候选人不能接受这种方式,国内这种现象确实也不少见。但换个角度来想,创业公司大多还在起跑阶段,需要的肯定是从事大量一线开发的人。如果面试通不过机考编程,或者是不愿意做题,这种候选人也未必能完全适合创业公司需要。而那些不愿意做一线事情的架构师即使进来,他大部分时候在分派任务或者强化流程,可能让公司的技术层级及开发环节变多、管理成本变高进而导致整体研发效率下降。

面试时候大家也认可的一些验证架构师能力的方法,比如把当前技术开发中遇到的一些典型性技术场景让对方来提出实现方案,以便评估对方是否具备应对类似场景的能力。在入职之后,可以让新的架构师独立承担及完成一些任务,以便考察对方是否具备独立的架构实现能力。

Pinterest的Feed架构与算法

Pinterest首页的Feed消息流,最早是按照用户的关注对象的Pin(类似微博)聚合后按时间进行排序(自然序,类似朋友圈),后来版本的feed系统放弃了自然序,而是根据一定规则及算法来设计,内部称之为Smart feed,其算法及架构根据其公开资料整理如下,值得业界做信息流产品的技术架构师参考。

Pinterest每个用户的首页feed都是个性化内容。Pinterest系统大约1/3流量都指向feed页面,因此它是整个系统最关键的页面之一。当工程师开发新版Smart Feed时,如何达到99.99%可用性也是衡量项目是否成功的指标之一。

Pinterest smart feed的主要算法及规则如下

  • 不同来发表来源的Pin按照不同的频次聚合。
  • 将Pin按照算法及权重有选择的去除(或延迟加载),质量较低的发表来源不必每次显示全部,系统可以有选择的决定哪些立即出现,哪些延迟显示。Pin的质量都是从当前接收用户的角度来衡量。
  • Pin排序的逻辑是最好的优先,而不是最新的优先。一些发表来源的Pin可能最新的优先,但另外一些发表来源的可能新的Pin优先级低。

Pinterest Feed如图所示主要由以下几部分构成,最左边是数据来源,最右边是用户看到的Pinterest瀑布流。中间的三个服务介绍如下。
pinterest-1

Feed worker

Feed worker职责:接收新的pin并根据接收的用户的不同赋予pin权重并保存。同一个Pin,不同的接收用户有不同的权重打分。
新的pin主要有三个来源:关注用户,相关内容,关注关系的感兴趣内容。Worker会给每个来源的pin打分之后插入到一个pool里面,每个Pool是针对单个用户的优先队列(Priority Queue,即优先级高的内容先出)。
由于Feed Worker按照接收用户的维度存储,因此所有的pin进入worker时候已经按照关注关系进行分发(即行内通常说的Feed推模式)。

Feed content generator

Feed content generator负责返回用户上次访问后新的pin。Content Generator可以返回前n条或者全部新的pin,用户获取过(即浏览过)的pin会从pool中删除。Content Generator可以将多个发表源的pin按照一定规则重新排列,但是不能改变原来的Priority Queue返回的优先顺序。即队列中高优先级的会被优先取出。

Smart feed service

物化视图用于保存用户上次feed列表的快照。此服务不需要对feed的重新排序,它将上次返回给用户的pin按照当时的顺序完整保存,由于它属于用户已阅读过的历史列表,读写较少,因此它可以提供更好的可用性。另外由于可以限制历史列表的长度,存储空间可控,因此可以更低成本来增加从库来提高访问的可用性。

Feed依赖content generator来提供新的Pin,如果content generator不可用,服务可以优雅的降级,用户仍然可以获取历史的列表,返回物化存储的结果。

Pinterest通过以上3个不同的服务,实现了对feed返回内容灵活的控制,每个服务都有自己明确的职责,达到了每个用户都具备个性化返回内容的目标。

Feed存储

Pinterest的feed存储需要解决以下几个需求:

  • 写入新发表的feed,由于Pinterest采用的是推模式,这个场景需要面临需要高的写入QPS,但用户能容忍一定的写入延迟。
  • 获取首页的物化feed列表,相对与写入的QPS要小很多,但是用户对请求的延迟容忍度低。
  • 删除feed。

可以采用简单的设计方法,比如将所有的feed写入到一个存储,可以简单实现访问、更新及删除功能。在Pinterest当前的访问规模有上百T的数据以及每秒百万访问操作。经过综合评估,选择使用HBase来实现了上述需求,Pinterest业务场景需要提供非常高的读写及更新操作,HBase同时提供较高的读写及更新访问性能。

用户发表一个新的Pin时,将Pin分发给他所有的粉丝,他的粉丝可能被shard到所有的HBase region上,因此一个分发操作可能要访问到多个region,并锁定每个region的WAL日志,然后进行更新再解锁。每次的write/delete/update操作锁定WAL非常低效,而且很快成为系统的瓶颈。更好的方法是将HBase的操作批量进行,并且可以加大HBase的吞吐能力,但另外一方面增加了访问的时延latency,如果是面向用户请求的操作,访问时延增大是不能接受的。

为了满足不同的需求,Pinterest设计使用了双HBase集群的方法,将数据在不同的阶段写入到不同的HBase集群的方法,请参考图示。
pinterest-3
Zen是一个在HBase基础上提供图(Graph)存储的服务。
SmartFeed Worker将用户发表的内容分发后通过Zen保存在HBase中,异步处理任务通过PinLater服务来调用。
SmartFeed ContentGenerator负责返回最新的Pin,并进行评分及排序。
当用户刷新请求自己首页的feed时,SmartFeed服务从Content Generator和物化存储的HBase归并数据返回给用户,如果生成服务请求超时,则系统仍然可以返回物化存储的数据给用户。在后台,SmartFeed将物化存储的数据从左边的存储删除。
在实际的场景中,物化存储HBase的数据远远要比发表池的数据要少,这样请求的速度会非常快。

Feed的高可用

使用上述设计后,系统的可用性相当于物化存储HBase的可用性。HBase集群目前存在GC卡顿的风险,还有单点故障region迁移等问题,因此使用单一的HBase集群,可用性很难保证99.99%以上。

为了解决这个问题,在另外一个EC2可用区启用一个备用集群,任何写入到主集群的数据将会在数百毫秒内同步到另外一个集群上。当主集群不可用时,可以从备用集群返回用户请求的数据。通过上述设计,整个系统的可用性达到99.99%以上(不包括写)。

pinterest-2

参考资料

http://pingineering.tumblr.com/post/105293275179/building-a-scalable-and-available-home-feed
https://engineering.pinterest.com/blog/building-scalable-and-available-home-feed

《火星救援》中你应该知道的5个高可用系统故障恢复原则

《火星救援》是最近一部受到广泛关注的片子,讲述在一次人类登陆火星的任务中,宇航员马克·沃特尼经历了一场恶劣的风暴后,与他的机组成员失联,所有人都认为他在这次任务中丧生。然而,马克却幸运地活了下来,然而他发现自己孤单地置身于异星球。面对贫乏的生命补给,马克必须用他的聪明才智和顽强的精神存活下来,并如何寻求求救的故事。

大部分互联网系统也面临各种临时突发的故障,技术负责人及相关工程师需要及时响应故障,采取合适的手段来解决问题。因此火星救援中体现的很多原则,做法和高可用系统故障恢复是同理。

1、故障信息的透明性原则

martian-1
在火星救援中,当NASA发现马克还生存时候,NASA第一时间再次举行了新闻发布会,向媒体及公众进行了交代,包括后续大部分事件如文本聊天,也是通过媒体现场直播,这是信息透明的原则。但是里面只有一点,NASA将相关信息给宇宙飞船的成员隐瞒了很长一段时间,这个是信息不透明带来后果的案例,后面面对公众时也出现了尴尬、被动包括可能需要承担职责的局面。

互联网系统在故障发生时候,技术人员第一时间发现了故障,如果不能马上排除,则需要考虑是否将问题上报、以及将信息公示给所有用户。

给公司上级上报故障在某种程度会对技术团队留下负面印象,给外界用户公示故障会给产品带来负面的印象及不信任。因此保证信息透明需要有一定勇气。但反过来思考,故障已经成为事实,也已经对用户使用系统造成影响,隐瞒问题会带来更多及更大的问题。技术负责人主动承认问题发生,及时通报问题以便各部门采取合适的应对及支援手段,以便能合理利用更多的资源来更早的解决问题。及时公示问题给用户(比如通过官方微博及官方网站),以便争取用户的理解及支持。

从长远来看,所有故障都不是某个人及所在小组的责任,管理层很少会出现迁怒于人的可能,而更多的是去改进体系上及管理上的问题。因此公开故障可以帮助公司及团队更好的、更透明的去认识问题,帮助技术团队做出改进,以便将来从体系上规避类似问题。

2、故障突发性对应的解决时限性原则

martian-2
火星救援中几个时间点都非常急迫。马克在火星的食品非常有限,并且可能会随时遇到不可预料的情况。尤其是当栖息舱爆炸后,全部种植的马铃薯死亡,且无法再次种植。瓦特尼只能倚靠之前收成的马铃薯生存下去,当时能让他再多活200个火星日。但是发射宇宙飞船登陆火星是一件非常庞大的系统工程,需要做好长时间的准备及周密的测试,并且存在欲速不达的可能。因此火星项目负责人需要在有限的时间内做出最佳可行的方案选择。

故障选择也大多处于类似被动的局面,当故障发生时候,用户访问系统受到影响,需要在尽可能短的时间内恢复服务。但由于时间紧迫,负责人可能没有足够的时间来分析故障的根本原因,只能根据现象及已有经验迅速做出判断。而且根据故障问题的不同,一些恢复手段如数据重建可能需要较长的时间,一些方案可能会超过用户容忍的极限,因此需要技术负责人在短时间内做出快速解决故障的选择。

3、故障中解决方案的技术决定性原则

martian-3
火星救援中,有几个场景体现了技术的决定作用。一个是中国的太阳神助推器,将宇宙飞船赫耳墨斯号推向火星,一个是航天动力学家里奇·布内尔的航行方案,可以看到,临时的技术方法在救援中起了决定作用。

故障恢复时候也有这样的情况,大家围着主要负责人旁边一筹莫展时候,突然角落里不起眼的程序员说找出了解决方法,然后非常及时的解决了问题。故障时候仅能看到现象,很多时候还没来得及分析出根本的原因,因此技术负责人也很难当机立断提出非常确认的方案来解决问题。熟悉体系的程序员这时候可以发挥自身的能动性,小范围的去推测、尝试及验证,有有很大的机会更快的解决问题。一些故障拖很长时间,有一定程度是团队成员没有有效手段,另外一个原因也许是团队成员群体思维,全部按照主流的思想或者负责人的思路去应对及处理,如果主流方法不是合适解法,有可能会将故障时间拉长。

还有一些公司将线上系统当成黑盒,工程师只需要将自己模块合并进去,无需关注线上运行状况。这种情况一旦出了可用性问题,大部分工程师是一筹莫展的,只能依靠少数几个精英来解决问题,通常不利于问题的迅速解决。

4、充分利用系统预留扩展能力的原则

martian-4
马克与地球取得联系,是依靠1996年发射的火星探路者号(Pathfinder),并且依靠其预留的通讯接口,让实时文本聊天成为可能。火星救援最后的决定作用是预留的MAV,通过下次任务战神四号预留的MAV上升载具起飞到太空轨道,然后对接上宇宙飞船赫耳墨斯号返回地球。这让马克在食品用完之前返回地球成为了可能。

我们在开发高可用系统时,大部分服务模块的代码都留了一个开关,可以在适当时候开启或者关闭一段代码。虽然在99.9%的场景下这个开关不起作用,但在灾难事故发生时候,可能一个小小的开关犹如发生故障时玻璃窗旁边的救生锤,可以决定整个事故的走向。

5、简单粗暴处理原则

火星救援最后的MAV起飞时候,由于上升高度不能到达赫耳墨斯号对接,因此简单粗暴的将所有没用的东西去除。看起来可能在电影里面才会出现,但如果真的碰到类似情况,可能也没有更好的处理方法。

在处理故障过程当中,很多时候也需要打破常规,用一些简单粗暴的方法,这些方法可能临时会造成一些用户访问的问题,甚至会引起部分数据的不一致,但是如果能让整体迅速恢复,这些简单粗暴的方法是值得鼓励和尝试的。关键技术负责人需要知道有合适的善后技术方案来恢复这些用户的数据。

马克·瓦特尼回到地球,许多天后的一天清晨,坐在公园长椅喝咖啡,原来我们写代码普通一天也是火星人羡慕的幸福生活。

本文中文翻译参考《火星救援》译林出版社中文版。