分享 | “三高”产品设计的这些坑,你是不是也踩过?(上)

供稿 |  eBay IE Team

作者 | 许健

编辑 | 顾欣怡

本文9432字,预计阅读时间29分钟

更多干货请关注“eBay技术荟”公众号

本次专栏分享,我们邀请了ebay基础架构工程部的研发总监许健,就设计高可靠、高扩展、高性能产品的主题分享他多年来的心得。共分为六个模块:稳定性/正确性、扩展性、高性能、过渡和迁移、整体考虑以及未来3-5年的挑战。此次专栏将分为上下两期,本期将着重 稳定性/正确性及扩展性 的探讨,其余敬请等待下期分享!

2016年5月24日,Sami(现任eBay数据基础架构部副总裁)与我们分享了他这些年来做技术的心得,其中一个主题就是 如何设计高可靠、高扩展、高性能的产品 。时至今日,在经历了这四年的各种“风风雨雨”后,我对Sami当年的话有了更多的深刻体会。本文中,我将引用Sami的一些“金句”原话,针对这些点,写写自己现在的理解,算是四年来对于这个主题的一段总结回顾,也希望能对大家有所帮助和启发。

一、稳定性/正确性

01

5%的代码,95%的测试。

5% Code , 95% Test.

在 eBay 这样规模的公司做项目,我实际的感受是, 50% 以上的时间用于设计讨论, 45% 用于测试调优上线, 5% 用于功能性代码(大家不要纠结具体的比例数字,大致就是这个意思)。

首先,设计讨论的效率跟这个团队里面技术领导的影响力直接相关 ,因为大多数的时间就消耗在“谁也说不服谁”上。也正是因此,这么多年下来,我养成了辩证看问题的习惯。 技术领导人独裁的时候效率最高,但是风险太大,一旦出现问题,整个团队就一起赔进去了。 所以,最好还是在强有力的主导下,大家都能没有负担地表达意见。

然后再说测试调优上线 ,我曾经问过我们Buyer Experience 和 Payment 两大部门的主管关于交付效率提升的主要困难,他们都把测试排在首位。大概4、5 年前,eBay基础架构的领导解散了集中的QE(Quality Engineer,质量工程师)团队,把原来的测试团队打散到开发团队中去。我当时觉得这样挺好的,从测试团队加入到开发团队的同学,既可以做测试还可以帮助开发。但现在来看,这一操作或许并非百利而无一害。我们需要有人专注测试效率,但并不是给开发团队做测试,而是跟开发团队一起去开发测试框架,团队业绩则需要考量CICD效率。现在市面上也有很多CICD的开源方案: Jenkins,Spinnaker,Tekton…

但是这些都不是重点,重点是要真的有人很专注地跟开发团队一起,从实际出发去做测试。 比如支付团队有很多Scrum Teams,多团队多项目做集成测试的时候需要多套 Staging 环境;监控团队需要利用生产环境的Request Replay来做LnP测试;Buyer Experience 团队需要利用Traffic Mirror 来做迁移(Migration)时的验证。这里多提一句,测试数据的准备也是一大问题,比如eBay大数据方面的测试到现在也没有一个高效的解决方案。如果大家对这方面感兴趣,可以看一下阿里巴巴的 自动回归测试DOOM。

02

万物皆会失效。

Everything will fail.

失效性测试非常关键,这里我举几个具体的例子,有些真的是血的教训。

我们部门出过一个28分钟的网站故障(Site Issue),导致eBay手机应用的流量直接降到零。原因是配置管理系统里的信息没有及时反映线上流量,导致我们在删除应用的时候认为该应用没有流量而做了误删除。网站大了各种妖魔鬼怪的配置都有,真是一言难尽,但是出了事故你是没有办法以这个为借口推卸责任的,弄的不好就是卷铺盖走人。

这件事情给我的教训就是,线上做删除操作时一定要擦亮眼睛,只相信设备返回的信息。这次事故以后我们但凡做删除,都会检查设备线上流量,而且先做Disable,Baking,然后再做Deletion。

我所在的是基础架构部门,网站可用性(Site Availability)就跟悬在头上的达摩克利斯之剑一样,需要时时刻刻注意。所以,我们会一直准备各种保底方案,以保证意想不到的失效发生时,也不会出大的网站故障。

年前我和Tess(eBay 基于Kubernetes 的下一代云计算平台)组的研发经理XG,网络架构师Jesse在会议室谈了2个小时,憋了以下 3个保底方案

a. IPAM(IP Allocation Manager)做IP分配必须有脱机作业(Offline Job)做IP冲突检查。

b. 网络配置DaemonSet 变更必须比对变更前后的变化,一旦有变化异常就停止变更。

c. Service Controller rollout 需要在生产环境设置 测试 命名空间(Namespace) 。由于测试环境和生产环境很难做到一样,所以必须要在生产环境里找一个测试命名空间,只有当该测试中的服务在变更前后没有异常时,才可以继续Rollout。

结果这些方案还没有来得及实施,我们的团队就在第二代Service Controller 的变更上碰到了问题,导致NuData(eBay下一代分布式数据库系统)在Staging 环境的服务不可用;过年的时候,分布式防火墙做变更,又导致正常流量被限制。 实际上,这两个事故都可以用上面的三个保底方案兜底。

像上面这样付出惨痛代价的教训有很多,但是成功的例子也不少,比如Tess(eBay 基于Kubernetes 的下一代云计算平台)团队对于API Server 做5000节点的失效性加压力测试就是一个好的案例。【 详情请点击 干货 | TESS.IO在大规模集群下的性能优化

总之,我觉得克服失效问题的关键还是思维方式和重视程度。要看你愿不愿意花大量精力,废很多脑细胞去想各种失效场景并且付诸实践。但这也只是对付你能想得到的场景,要想做到未雨绸缪,你还得多烧一些脑细胞去想想保底方案。

03

一定要设计服务降级逻辑。

Always have a degraded second path.

关于服务降级逻辑,这里展示3个真实案例。

第一个案例在当年造成了eBay长达40多分钟的网站不可用,可谓代价惨痛。当时一个叫.vip的顶级域名刚刚生效,不巧的是,eBay内部不少服务用的都是短名访问,比如访问服务A,就是 A.vip。所以在.vip顶级域名生效的时候,eBay 网站大量服务就不可用了。

我记得Sami 有一次跟我说过,他设计ZOOM(eBay商品图片存储系统)的时候就考虑过 DNS 不可用 ,所以他在ZOOM 里面会缓存最近的DNS 解析。当 DNS 不可用时就尝试用缓存的IP。去年,总部流量管理部门的方案架构师Charles曾经给我看过一个他处理的问题:业务团队汇报当服务A 访问服务B时,每隔一段时间就会有延迟。最后查下来这个时间点其实就是本地DNS 超时缓存的时候。 他后来给的建议是,添加一个脱机(Offline)的逻辑,在该时间点到达之前就刷新本地DNS 缓存,以保证服务A访问B 时不做按需 DNS 查询。 这类缓存策略在跨部门服务依赖的时候也会用到。Altus(eBay 内部的应用管理产品)依赖于IT 部门的DL manager,但是自从出现过几次跟DL manager 性能有关的事故后,Altus 就开始缓存DL manager 的数据并定期刷新。可见,服务降级逻辑至关重要,这也是我们在亲身体会后的经验总结。

第二个案例发生在3年前,上海的Rheos(eBay 基于Kafka的消息中间件系统)团队一直抱怨C3(eBay Openstack)不稳定,而从C3 的角度看可用性一直是好的,十分奇怪。后来我们跟Rheos 团队坐在一起看,才发现Rheos Cluster对那些彻底死掉的VM(Virtual Machine)竟完全免疫,反而是某个活着的VM发生性能下降(很多时候是磁盘性能下降),会对Rheos整体性能产生巨大影响。

我们当时还做了统计, 40% 的物理机器的磁盘或多或少都有一些问题(比如坏道),但并不是Rheos 40%的机器都受到性能影响。况且,我们也没有那么多预算替换40%的机器, 所以后来采取的办法是监控磁盘错误的增长速度,如果发现错误增长率在提高,我们就主动替换机器 。这个功能上线以后客户体验就得到了极大提升。

第三个案例是依赖的失效问题。我们的PAAS 系统因为依赖很多,可靠性一直得不到保证。后来PAAS 团队的架构师Jonathan把PAAS的依赖做了分类,对于关键依赖,只要一点失效,PAAS 就也跟着失效,而对于非关键依赖,就看是否可以接受最终一致性,再加上刹车保底,脱机作业不停修复数据等一系列举措,可靠性终于得到了保证。

如果我们站得更高一些,从整个公司服务治理的角度来看,可以给每一个应用标记重要性级别,高级别应用依赖低级别应用必须设计降级逻辑。但是真的实施起来却很困难,迄今为止,eBay 也没有能够强制执行。我个人觉得,如果可以把Chaos Monkey 的逻辑构建在系统上线的流程里面,或许会好很多。

04

保证数据输入的有效性,时刻检测以预防数据损毁,帮助恢复逻辑。

Ensure input data is valid. Detect, prevent, recover from data corruption.

有一类坑我们曾经掉进去过 3次 ,这个坑就是 Sync 类问题 。我们从Source Sync 数据去同步Target,结果由于各种原因从Source 读数据时发生超时,没能拿到数据。一开始还误以为是Source 的内容是空把Target 给抹掉了,实际上是因为读超时返回空,却没有正确地错误处理逻辑。

这里我要强调一下兜底原则,对于变更,最好要设置一个变更限额(Change Quota),超过限额数目的变更就应该停下来,发出告警。这里扩展一下,现在很多Cluster 都会为了高可用性(High Availability)在多个可用性区域(Availability Zone/Region)进行部署,然后做跨区域同步。但同时我们也要意识到,错误的数据和操作也会很快同步到所有的Clusters,风险极大。所以我更要强调,做变更限额,特别是跟删除有关的变更限额的重要性。

再展开讲一下前面提到的IPAM(IP Allocation Manager)对于Duplicate IP检测问题。 网络组交给IPAM的可用网络段(Subnet)是不能全信的,必须做校验。 就算有了校验,也还是不能尽信,因为指不定就有人绕过系统在某处起一个服务,使用IPAM 里标记可用的IP。不要说什么人家绕过系统自己起服务是不对的,世界就是这么处处充满“惊喜”,我们要做的就是无论如何,都尽量保证不出网站故障。

回顾我在基础架构部门的实际工作经验,碰到最多跟数据有关的就是CMS(Configuration Managment System,配置管理系统)和设备里的脏数据了。你要做一个操作,就要先操作设备,再操作CMS,但是因为没有事务处理(Transaction),就会留下脏数据,或者由BUG 导致留下脏数据。而清理脏数据是一个又脏又累又危险的活,这个问题到现在还是没能得到很好的解决。但没有好的解决方案不代表没有好的模式总结。

我的经验总结就是:一旦系统牵涉到数据,就要考虑定时的数据完整和有效性检查。如果要减少检查的量,那就把每一次正常服务客户的请求当成一次数据检查,也就是说给数据打上检查的时间戳,额外的检查和正常服务客户的请求都会更新这个时间戳。

这里再说两类情况。

我们监控系统的Metrics解决方案是基于开源监控系统Prometheus的,但是限制并不能很好地支持高基数(High Cardinality)的情况。那我们该怎么来检查高基数性并且做系统保护呢?现在能采取的办法是设定一个阈值,超过这个阈值就限制后续的数据。但其实这个时候影响就已经造成了,未免有些为时已晚。所以我觉得应该检测基数性增加速度,从而提前防护,或许效果会更好。事实上,淘宝搜索引擎在新上架商品搜索评分上就用了类似的方法:最近7天的销售增长速度。

第二类大家听了可能会发笑,但却是真实发生的故事。我们的搜索引擎在处理一个错误查询时触发了一个BUG,导致处理该查询的节点崩溃。有个工程师很快发现了这错误查询并且发邮件给整个搜索部门告知他发现了根本原因,还在他的邮件里贴了错误查询的链接。结果看邮件的人都去点击了这个查询,我们差点被自己人点死…这一教训也算是让人印象深刻了。

05

简单即美,减少模块数量和模块间交互。

Keep it Simple. Reduce the number of components and interactions.

我在这里强烈推荐一本叫做《极简设计》介绍UI 的书。我觉得读了这本书以后可以给心里种下一颗“极简”的种子,之后做什么事情,都会努力去想,我的方案够简单吗?要有这种追求更简单的精神。还有一本书叫《精进,如何成为一个很厉害的人》,里面有一个观点就是,很多人思考问题,一找到答案就停止了,而有的人还会继续寻找更优方案,这里的更优方案,其实就是更为精简的方法。

事实上,不少遗留很久的问题最后的解决方案都是精简系统。比如,我们的CIaaS系统上Volume Attach/Detach稳定性长期得不到保证,原因就是Nova和Cinder 数据不同步(我们的Kubernetes Dev VPC Cluster是跑在Openstack Dev VPC VM 上的),后来的解决方案就是一不做二不休,干掉Nova,通过VM on Kubernetes 直接调用Cinder,效果非常理想。【详情请点击: 分享 | 基于kubernetes的VM解决方案探讨

但我现在仍然觉得我们的Altus(应用管理产品)系统不够精简,调用层次太多,仍旧需要改进。我非常推崇 奥卡姆剃刀原则 ,即“如无必要,勿增实体”,这一“简单成就高效”的原则适用于很多场景,非常实用。

06

尽你所能地去解耦模块。

Decouple components as much as you can.

估计所有设计模式的书都会介绍模块解耦问题。自从微服务这个概念出来以后,大家就倾向于部署大量组件。 我的建议是,就按照微服务的思路去设计,因为分开部署是需要模块化的,但是设计的时候尽量做到既可以打包在一起部署,又可以分开部署。 不要动不动就搞分布式,后续运维排错成本是很高的。比如A 调用 B,如果打包在一起就是一个函数调用,要是用两个HTTP服务,就牵涉网络了,要考虑延时,要对基础架构提要求有没有分布式日志等等,还要消耗负载均衡器(Load Balancer)的资源,十分繁琐。所以能简则简,但如果你真要用分布式部署,就只做一个配置改动即可。

这些都是经验所得,都有实实在在的案例。监控组架构师Huai 曾跟我说,我们分布式日志基础架构的容量(Capacity)必须每年增长 60% 才能满足需求。然后我们就觉得不对啊,我司业务哪有每年增长60%?后来碰到Sami,我就问他这个问题。他是这样回答我的: 微服务贡献了很大一部分日志,本来一个系统,现在N个系统,日志就增加N倍。 而我们公司的物品增长速度远高于买家的购买增加速度。比如你增加了 30% 的物品去卖,尽管交易并没有增加,但是我们公司内部的各种大数据服务都要去处理那增加的30%的物品。这些服务不仅增生了更多的日志,还要消耗计算存储网络运维资源。所以回到 奥卡姆剃刀原则 ,代码设计的时候要用模块结构,但是不要一上来就部署一堆服务,也不要学了一点Restful,就把所有的接口都搞成 Restful。

07

高可用不是可选项,而是必须项!

HA is not optional!

高可用的必要性众所周知,真正值得探讨的是高可用的执行问题,这也是难点所在。上文我提到过,只有把Chaos Monkey 做进应用上线的流程中,才能保证其执行。在我们公司,很多服务都是通过Altus这个产品来做应用创建、上线的,那我们就把一些最基础的高可用检测做进上线流程(go live process),比如关掉若干台机器,注入一些网络延迟和丢包,弄个磁盘只读等等…

但我在这里想说的其实是另一个层面的事情,也就是我们公司的员工。 一项工程要长久,除了满足公司的业务需求,还要满足员工个人的发展需求。 如果就是做做上面的那些上线流程检查,对我们的员工自己的成长又有多大帮助呢?特别是我们基础架构部门的人,很多项目都是中间件,框架级别的产品,对性能和高可用的要求特别高。我觉得非常有必要把这件事花足够多的时间做透,毕竟高手都是锻炼出来的。我们需要提供这样的场景来把系统在各种情况下的问题逼出来,然后在解决的过程中去理解,去挖代码,甚至持续数周在一个问题上不断钻研。低水平的重复对我们员工的个人成长毫无意义。

而且,这样的投入对整个公司也是大有裨益的。我们基础架构部门的客户其实都是内部客户,用XFan(eBay 数据基础分析平台负责人)的话说我们的内部客户真的很好,他们没有什么要求,也不需要我们提供多少功能。就那几个很简单的功能,保证永远可用,再加快点速度就好了。

我们要有工匠精神,就把这几个功能做好。但是规模扩大后,你会发现,就这几个看似简单的功能,要做到永远可用,再加快点速度,还真不是一件容易的事情。

很多问题都是我们试出来的。如果你的系统分控制面和数据面,那就做一个实验,看把控制面关闭后数据面有没有影响。如果你的系统有自我修复能力,比如丢失心跳就会触发 Cluster 内数据再平衡(Rebalancing)或者 Kubernetes驱逐节点负载(evict node workload),那就试试心跳都丢失的情况,看会不会产生灾难性后果。

千万不要轻信开源产品,特别是当你要把开源产品投入生产环境时,一定要有“忧患意识”。你可以把生产环境的流量 乘以2 (Sami 说他做eBay 商品图片存储系统ZOOM 的时候 乘以 5 ),然后做压力测试,做故障模式分析。我们部门的Shone 现负责Feature Pool Software LB 解决方案的实施,他曾部署Istio以解决feature pool的问题,他的学习体会里就明确写到,不经过自己的验证的前提下,绝不能轻信开源代码。

总之,对于大环境下发生的事件要敏感一些,比如上面提到的.vip 成为顶级域名的事情,比如闰秒问题… 我现在的指导原则是,如果可以,就尽量少堆一些逻辑,多做一些深层的工程设计。 Rami (eBay 基础工程架构副总裁)对我的要求就是不要搞出会影响ATB(Availability to Business,企业可用性)的大型网站故障,不要把RTB(Run the Business)掉在地上,要把团队往深层工程设计实施方向转型。

08

安全问题,切忌事后诸葛亮。

Security is not an afterthought.

安全问题绝不能事后诸葛亮,大家都明白,但能真正做到的其实很少。这类问题我其实接触得并不多,一些知识还是最近一年积累的。想要了解这方面内容的,可以看一下《白帽子讲 Web安全》这本书,很有帮助。

就我所在的IE(Infrastructure Engineering)部门而言, 日常工作中主要有两类事情跟安全有关。

一类是PCI Audit,我们的不少服务都要通过其检验。我觉得很有必要去看一下 PCI DSS 的规范,否则在公司Security 团队面前很容易变成一个牵线木偶。 还有一类就是IE部门推出的 Certificate,Key 和 Secrets 的生命周期管理套件 ,配套的还有Trust Fabric ,具体的内容我们后续也会在“eBay技术荟”公众号上与大家分享交流。

现在的应用程序渐渐不再使用用户名密码的方式来做认证授权了,毕竟定期变更密码实在麻烦得很。这里推荐大家看看Kubernetes 里Service Account 的实现机制,就能知道怎么让你的应用不要为用户名密码烦心了。网络安全是个很大的方向,需要长期积累。如果决定要做安全领域的工作,那就持续投入,在这个方向上死磕个2-3年,我相信肯定会有收获的。

09

用监控和告警实现100%的可见性。

100% visibility through monitoring and alerting.

争取用监控和告警实现100%的可见性,当然,100%很难做到。我们部门有位同学就对量化有执着的“咬文嚼字”精神。与他谈话,不要用100%,All, None这种绝对词,因为你一说他就不信;也不要跟他用Many,Less 这种非定量词,因为他会反问你:“Many? Tell me how many.”

所以这里的“100%”,估计Sami就是强调一个精神了。 我们公司Payment 部门说没有监控就不能上线,我很赞同。 我觉得什么事情都不能尽信,什么幺蛾子都会出现。比如,监控告警的邮件地址配错了导致收不到告警邮件,于是在系统恶化早期没有被通知到,直到系统崩溃的时候被SEC(Site Engineering Center)打Oncall电话才知道;而美国打中国的Oncall电话一接就断线甚至打不到…这一系列幺蛾子我们都经历过,都是血和泪的教训。

正在看这篇文章的同学,你们是否也遇到过这样的问题?邮箱里面收告警的文件夹有着上千封未读告警邮件,每天都在读或不读中纠结。我就有好多个这样的文件夹: IAAS Alert/ PAAS Alert/ Reparo Alert/ C3 Alert/ LBMS Alert/ UDNS Alert/ Tess Alert…根本看不下来,最后也就不看了。

狼来了的故事大家都知道,我觉得我们日常工作中碰到的问题往往不是告警太少了,而是太多了,然后真的出了个大事故说不定还没有告警,想想真是胆战心惊。

就我这些年的经验来说,我个人认为以下 告警设置 还是比较实用的:

1. 将系统最主要的客户用例列出来 ,然后写个Cron Job 不停地对着服务Call,成功率不达标就报警。

2. 记录客户的真实请求的成功率,成功率不达标就报警。

需要注意的是,整体的高成功率并不代表其中某一个客户的成功率很高 ,所以对于重要客户要有专门的细分。

除此之外,最好能亲自跟客户确认一下,这样设置告警是否体现客户体验。 这点很重要,因为客户的需求并不一定与你的想法一致。 比如我上面说的跟Rheos(eBay 基于Kafka的消息中间件)团队的交互中就发现,我在乎的VM 的Up and Down 并不是Rheos 团队最关心的,他们关心的其实是性能的稳定。

3. 在集群部署的情况下,要引入异常检测 ,一旦集群中某个节点的关键指标和其他节点出现明显不一样,就发出告警,甚至可以直接拿掉那个节点。

拿掉节点的时候要写原因,并且有后续流程保证修复后加回Cluster。我们的C3环境曾发现很多被Disable的节点但又没写明原因,造成了不必要的浪费。

时间上引入的异常检测主要是看当前时间的趋势和之前的是不是变化很大。平时要做Drift 巡检,很多问题其实都是由于各种配置的Drift 造成的。 对变更要敏感,问题不会凭空产生,一定是发生了什么事情。 如果你自己做变更,除了关心自己的关键指标,还要关心上下游的关键指标。我们公司的LOM(Lightout Management) 会在工作人员部署代码的时候自动检测上下游服务。如果发现上下游关键指标异常就会暂停当前变更等待负责人员确认。真正在线上出了问题,第一考虑的都不是找到根本原因,而是恢复服务,所以一定要有一个工具来迅速找到最近的所有变更,然后做Rollback。

二、扩展性

01

选择正确的扩展模式。

Choose the right pattern for scalability.

我觉得 CAP定理 还是值得学习一下的。

CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition Tolerance(分区容错性),最多只能同时实现两个,三者不可兼得。

每一个方向都会有一些基础性的理论,往往就是那几篇大佬写的论文。 找到这些论文,多读几遍,对今后的学习工作很有帮助。 国内很多做技术的组织都叫研发中心,其实大多数哪有什么研发,只能叫工程中心,是做实施的。我们应该多读读论文,读经典的论文,培养自己读懂论文的感觉。

02

需要持久化的部分是最难做高扩展的,

就从那里入手吧!

Persistent state is the hardest to scale.

Start there!

其实何止是持久化,任何一个系统我们都需要知道瓶颈在哪里,然后从那里入手。解决了一个瓶颈就要看下一个。假设原来的瓶颈在IOPS,结果用SSD 换了Spin Disk后,CPU的问题就浮出来了,又是一个瓶颈。建议先读一遍《大规模分布式存储系统:原理解析与架构实战》扫一下盲,eBay 的上海存储组开发经理ZhiTeng 当年还建议我们去学习CRUSH算法,这是Ceph的基础。我还记得他有一句话:“高性能高可靠性存储就是给懒程序员准备的。”

其实懒程序员没有什么不好,能花点钱解决的问题不一定就需要死磕高技术的。eBay云计算进行到C3(eBay 基于Openstack的云计算平台)阶段的时候,Debashis(前eBay基础架构副总)说他在推动整个eBay 的应用变迁到云原生 (Cloud Native) 上也感觉到困难重重。他问我们是不是就应该投资SDN(Software Defined Network,软件定义网络),做IP移动和共享存储,有了这两个“帮手”,大部分有状态(Stateful)的问题都能转变为无状态(Stateless)的,而且对于eBay的大部分业务APP来说也足够了。

如果真的决定要用更先进的技术栈来解决现在的问题,那做性能测试必须清楚地知道 性能瓶颈 ,压力测试的时候如果CPU、内存和IO都没有满,就继续测,测到其中一个满为止。压力测试的时候,注意压力测不上去的原因也可能是客户端不够强大。

03

了解依赖服务的亲和性,并进行相应部署。

Know your affinity to dependent services and deploy accordingly.

从可用性来说,要明确各个级别的失效域(Fault Domain),比如物理机器挂了怎么办,机架上的交换机挂了怎么办,一个可用区(Availability Zone)挂了怎么办…

做扩展的时候也要考虑这个问题。之前我们的CAL分布式日志是依赖组播技术的,但是eBay 数据中心默认组播是关闭的。于是为了CAL ,将其所在的网络 Bubble打开组播,但这也导致CAL 做扩容的时候限制颇多。后来监控组重构了CAL 去除了这一限制。【详情请点击: 分享 | 低延迟高吞吐的CAL Ingress

我觉得特别是对于性能和带宽有要求的服务,一定要重视服务所在的基础架构环境。以网络延迟和带宽为例,要清楚地知道,在同一个机架(Rack)内,跨机架和跨Bubble的区别。你得知道物理限制,比如Hadoop集群做存储计算分离时,就必须考虑网络带宽和延迟。eBay的搜索引擎对性能要求很高,基本上在做设计的时候就要考虑亲和性,比如一个查询聚合器/调度器(Query Aggregator/Dispatcher)要分发汇聚一批查询节点(Query Node)的信息,在部署的时候就要特意把查询聚合器和该聚合器负责的查询节点部署在同一个Rack内部。公司内部还大量使用ZooKeeper,监控组跟我说如果ZK Cluster跨区域(Region)部署,出现脑裂(Split Brain)的比例就会变高。

04

复杂的操作并不总能实现高扩展。

Complex operations are not always scalable.

复杂的操作并不能保证高扩展性,所以尽量不要有复杂操作。

比如eBay 的Oracle DB 上默认是不能跑存储过程的,也非常不建议搞分布式Transaction,因为这些都无法进行扩展。还是那句话,在你试图解决一个复杂问题的时候,不要一下子就沉进去,先想一想是不是可以不那么复杂,有没有更简单的方法?在公司里,一个统一的解决方案(Unified Solution)并不一定需要一个很大的集群,也可以是多集群并存。所以说,做事情先问为什么要做,再考虑怎么做。

05

预先计算,切勿繁杂。

Pre-compute and keep it simple.

在考虑实现方式前要先搞清楚需求,世界上没有免费的午餐。如果做预计算,我们就要处理预计算和实时计算之间的不一致和同步。Apache Kylin 就是预计算,我们在工作中对更新频度不高但是会查询大量数据做预计算。如果你要直接面对用户交互,最好明确告诉用户你的查询结果是基于什么时间点的预计算结果,以避免后续的纠纷。

做预计算就一定会牵涉到同步问题。我的经验是,同步的时候增量同步和全量刷新同步都是需要的。增量同步往往是事件触发类型的,难免有遗漏,遗漏新增数据和删除数据,这些遗漏可以靠定期的全量同步完成。全量同步的时候需多加注意,要设置一定的变更配额(Change Quota),避免把“病毒”也做大量同步。

06

考虑分区、并行和微服务。

Think in partitions, parallelism and micro-services.

分而治之,专人专项,这些在我们人类社会常识和设计系统的时候用的思想其实是一样的。关于并行,我们要考虑的是在并行的过程中是否引入过多上下文切换(Context Switch)。我们自己在工作中尚且知道要专注,不希望被打扰,程序也是一样的。对于微服务的态度,我在前面已经谈过了。

07

优先选择可扩展的算法而不是复杂、酷炫的算法!

Always choose a scalable algorithm over a cool and complex one!

eBay 总部流量管理的方案架构师Charles曾经跟我说,他纵观人类历史,凡是能够经久流传或者得到广泛应用的都是那些简单的能够以低成本复制的东西。我深以为然。Charles就像是那种学了哲学来做技术的一类人。或许,计算机科学归根结底也是一门哲学。

CRUSH 算法对我影响颇深,导致牵涉到 Hash、Mapping 的时候我都会想有没有办法用一个公式就能完成所有的Mapping 呢?一个公式才多少个字节,要是真能实现,那得多么神奇!这让我联想到生命,生命源头的受精卵就是那个最初的算法,或许这个算法只是一个非常简单的公式,但它却能让一颗细胞不断分裂复制,到成长为一个复杂构造的人,一个生命的大型分布式系统,并储存如此之多的信息。这是多么伟大而神秘的算法!就像爱因斯坦的E=mc²,极简的方程式阐述了极复杂的质能关系;就像道家的“一生二,二生三,三生万物”,极繁的根源,或许就是极简。

当我们处理计算机问题的时候,试试哲学的思维方式,或许能有新的领悟和视野。其实很多程序员的书单里面都会有很多历史和哲学书,为什么呢?销售学上有经典的啤酒和尿布一同摆放售卖从而相互促进销量的故事,我觉得程序员和历史/哲学也有类似的联系。一个好的程序员不一定有历史哲学思维,但一个会思考历史哲学问题的程序员,绝不会差到哪里去。

08

用监控和告警实现100%的可见性。

100% visibility through monitoring and alerting.

某同学:欸?这话怎么有点眼熟?

某作者:没错,就是 第一章 09 !原模原样!

某同学:哈?那为什么第二章又要讲一遍?

某作者:  因为人类的本质是复读机

因为重要的事情说三遍啊!!!

小结

本期分享主要从 稳定性/正确性和扩展性 这两个方面,就如何设计 高可靠、高扩展、高性能产品 的主题进行了总结和回顾。希望各位同学能有所收获,也欢迎大家在评论区进行友好的探讨。下期分享的主题为:高性能、过渡和迁移、整体考虑以及未来3-5年的挑战,敬请期待,不见不散!

作者简介

许健,2007年加入eBay 任搜索后端开发工程师,后从事云计算相关工作。在eBay 先后经历搜索后端架构从SPARC 到X86 转型,配置管理系统从ODB 到 CMS 转型,IAAS 和 PAAS的开发,经历eBay 云计算平台从 Stratus 到 C3 到 Tess 的过渡。现任eBay 上海基础架构工程部研发总监。

您可能还感兴趣:

一探究竟 | eBay流量管理之看不见的手

解密 | 一桩由数据洁癖引发的DNS悬案

分享 | eBay流量管理之Kubernetes网络硬核排查案例

分享 | eBay流量管理之负载均衡及应用交付

案例分析 | 由Decimal操作计算引发的Spark数据丢失问题

超越“双十一”—— ebay百万TPS支付账务系统的设计与实现

干货 | 起底eBay Flink的上云之路

:point_down:点击 阅读原文 ,一键投递 

 eBay大量优质职位,等的就是你!