*大师兄说:
众所周知,对于现在国内的互联网环境,不管什么样的系统,一旦等用户的访问量上去之后,我们每增加一个功能实际上都是要考虑它的吞吐量和延迟,在加工上都是要做一个缜密的思考的。所以我相信在这方面许多人都有自己一些独到的见解,有许多人也会对这方面比较感兴趣的。所以我们这次就组织了一个关于性能优化的话题。*
全网首发·技术干货·大咖对话
整理:魔窗丨 15618字丨20分钟阅读
来源:本文整理自跨境茶话会线上分享,为魔窗(magic-window)原创首发,转载需获得授权。
【主持丨大师兄】:大家好,我是本次跨境茶话会主持人张申竣,朋友们也可以叫我大师兄,目前担任魔窗CTO。我先介绍一下本期嘉宾。首先介绍一下我们的耿茂。
【嘉宾丨耿茂】:大家好,我叫耿茂,我现在在Pinterest做SRE工程师,之前是做过多年的性能工程师。
【主持丨大师兄】:我们介绍第二位嘉宾王羽嘉,来自Splunk,和大家打个招呼吧。
【嘉宾丨王羽嘉】:好的,大家好,我叫王羽嘉。之前在EMC和现在在Splunk都是做性能工程师,当然我目前主要是负责性能测试的自动化、性能测试的快速迭代的项目。
【主持丨大师兄】:第三位嘉宾是任志超,他目前在小红书是整个测试团队的负责人。
【嘉宾丨任志超】:大家好,我是任志超,现在在小红书,目前负责整个测试团队,前面也在做一些我们小红书性能保障和全链路压测的一些事情,所以很高兴有机会跟大家做一些分享和交流。
【主持丨大师兄】:我们接下来第一个环节是想请三位嘉宾分别谈一下他们在自己公司所做的一些关于性能优化和性能测试方面的一些最佳的实践,志超你先来谈一下吧。
【嘉宾丨任志超】:可以,从我个人的一些历史经验来看,我觉得在互联网企业里面,因为我前面在蘑菇街大概工作两年,然后又来到小红书,现在大概有半年多的工作经验,大部分的时间可能会跟不同的业务场景和业务产品下面的性能压力打交道。
我个人认为在不同的业务模式和互联网的场景下来,性能保障和优化是一个需要考虑不同场景下的一个综合考虑的命题。事实上同一套方法论或者同一套优化理论在不同的业务模式下可能是完全不适应的。在小红书这块,因为实际上它是分为两块,一块是电商,另外一块是社区。在这两块不同的产品下面它的性能的优化和稳定、调优都是不同的方向。从我这边的感触来说,对电商来说更多的是,第一它会有一个峰值,从电商的峰值来说,对于大促通常是十倍以上的平时的压力。在这个地方我们更多的考虑是说在峰值情况下的配比,以及基于它的不同的架构模式下我们怎么找到压力的平衡点,基于压力的平衡点,我们预先对这一段压力在大促前进行扩容,来保证它的平稳通过。也就是说对于像小红书这样的企业来说,我们更多是简单粗暴,如果能够解决当前的问题就先解决当前的问题,然后再从架构层面我们怎么去拆微服务,怎么去做隔离,怎么去把数据迁移出来,把核心的链路保持稳定,以及做好整体的监控。
但事实上在整个优化过程中说实话离不开各个技术岗位的配合,其中就包括我们的产品,甚至包括我们的运营,包括我们的研发团队,包括我们自己的测试团队,包括我们运维的体系和实时响应的效率。我分享几个场景,第一是在整个电商业务的66大促保障过程中我们是提倡一直到66前的一天我们还在做业务的开发。在这种情况下整个66大促的性能的保障,我们更多是结合业务的开发同步进行一些业务场景的梳理和配比的调优。在这种情况下我们同时做线上的性能压测,以及基于线上性能压测快速地做扩容和迭代。如果找到一些敏感瓶颈点,那我们会及时对这个瓶颈进行处理。同时在每一个所谓的我们可能发生问题的瓶颈点,我们会加大监控和线上数据采集的力度。在这种时候,我们实施上第一,责任到人,每个节点我们会有对应的责任人。第二,做好应急预案,对于每一块的业务,担心它出现问题的时候,我们用什么样的应急预案。第三,我们做好前期的数据的隔离,事实上我们在大促前做了几个业务系统的数据迁移。基于这些数据迁移我们可以保障我们的核心内幕尽量不要有其他的业务数据会打到我们的核心数据上面来,保证我们核心数据的统一。
在整个的过程中我们事实上还会碰到各种各样的一些问题的,所以在小红书这一类的企业更多是整个性能压测和性能条有是持续改进和持续变化的工作。相对来说假设我们是在一个大公司,比如阿里、京东这一类的企业,他们第一是更有计划性。第二,可能会相对来说有更多的时间来投入在整个的性能保障和压力上面。比如说他们在双十一的全链路保障上面,他们可能从7月份开始就已经开始做今年的双十一的整个的性能的准备和压测了。事实上,比如说小红书,我们如果在做今年下半年红五的大促保障的时候,我们可能要到9月份,甚至10月份才开始。而这个过程中整个大促的开发,还有整个大促的业务的演进可能都还在进行中。
所以从这一点来说,不同的互联网的工作模式和业态,以及公司的当前所处的阶段会决定你对于整个性能和线上业务稳定性保障的不同的策略。这是我从小红书和以前蘑菇街的经验来看到的我的一些感悟。
【主持丨大师兄】: 好的,非常感谢。接下来羽嘉你讲一下在Splunk的目前关于性能方面的做法。
【嘉宾丨王羽嘉】:ok。刚才志超这边讲了很多在互联网行业这边确实是比较传统的做法。但是在Splunk这可能是一个非常特别的案子,因为Splunk本身它的业务场景就很特别,首先它的定位就是一个企业级的软件,可能跟互联网的行业差距比较大。简单先说一下Splunk的场景是什么,他本身主要像我们大家都知道的ElasticSearch一样,他们都是对非结构化的数据做索引和搜索的。所以这种行为更多是面向比如说IT的管理人员或者说是devops,他们可能会更多地使用Splunk这样的产品。
它的场景其实主要可以分为两类,一个就是做索引,一个就是做搜索。所以我可以简单说一下针对索引和搜索这两块我们是怎么考虑它的性能的。首先说做索引吧,其实它的索引行为其实也是很简单,比如说我们会指定某一类的数据源,对这个数据源我们会把它的数据首先要抓出来,然后扔到Splunk里面去做index。这个行为我们可以理解为它是由多个管道串联起来的,第一个管道就是我首先要在数据源的性能以及Scalability可以保证的前提下,这样我可以使用多线程并排的方式去从一个单一的数据源里面把数据都抓出来。
我举个例子,比如说我们可能会对AWS S3这些所有的key做抓取,那我可以用多线程的方式把它都抓出来。通常是多个管道(pipeline),其实我们这边的做法也比较传统,多个管道连接的话我们都会用到Queue,我把数据抓出来之后我会把它扔到一个Queue里面,然后由下一个管道的具体的线程去处理我的Queue里数据,从而传输到我的下一层管道里面。这样的话,如果考虑是不是在我的多个管道连接的过程当中,会不会有一些瓶颈的存在,我们会monitor每个Queue的size和length,就是看每个Queue当前的一个累积的数据数量是多少,那么我从而可以定位到具体是哪个管道的行为比较慢,这个我们可以再继续做优化。
另外一个点,因为我们涉及到多线程从一个pipeline里面去扔到另外一个pipeline里面,所以必然会考虑到写checkpoints,因为只有写checkpoints的话才能避免我在一个多线程去抓数据的时候能够保证数据没有重复,并且没有丢失数据。一般来说checkpoints的读写其实有很多种方式可以做。当然比如说读写内存或者是文件,或者是数据库,那这样的话我们要去考虑我们想达到的throughput是多少,当然可能性能最优的就是对数据库的读写,同时也要考虑我单独去衡量我这个数据库读写的性能能够达到多少,从而可以保证我一个点对点的总体的吞吐量是多少。这个就是我们抓数据,并且对数据做索引,整个的flow是这个样子的。
如果是另外一种场景,就是做搜索,做搜索的话其实是完全又不一样的。Splunk我们这边用的搜索语言叫SPL,是我们自己的做搜索的一种比较特别的Language,大家可以理解为就像我们在查询数据库用SQL一样。这个语言其实本身一样可以像SQL一样写得非常复杂,包括有嵌套,包括也是类似于用一个管道去连接的。所以可能超过百分之六七十以上的情况你去优化搜索行为的话,更多你要优化你的SPL,在这个语言上的优化可能是占的比重比较大的。而且我们的搜索虽然是给用户直接使用,但是它的主要的面向对象可能很多的情况下是IT或Devops,所以它对于搜索的高并发要求并不是非常高。所以我们通常来说可能十几个用户是一个非常高的并发量了。
对于搜索我们其实也有一些优化的考虑,这个可能跟Splunk自己的一些技术相关系。比如我举一个例子,Splunk做索引和搜索跟ElasticSearch最大的差别是,像ElasticSearch更多是说我在数据进来的时候我会把对应的那些字段抽取出来,并且做index。但是Splunk恰恰相反,它对很多的字段其实并不是直接被写到index里的,它还是都存在于你的raw data的,也就是说我其实在进index的时候这个行为是非常快的,但是做搜索的时候其实在搜索的runtime里面会把你的字段再重新抽取出来作为你可以看到的字段。所以这个行为就会导致你的搜索其实是比较慢的。在这块我们有很多的优化方式。主要目的就是让用户可以更加动态,更加灵活地使用我进来的这些数据。这可能是一个比较大的话题,比如Splunk支持把一部分的字段的数据或者一定时间范围内的数据写进index,这个是可以在数据进来的后期去做的。其实在这块是一种逻辑层面上的优化,但是这种优化对用户直接的使用的体验效果会非常好。这只是一个例子,如果更多人有兴趣的话我们其实可以再去讨论更多的细节。
这边主要是我这边的一些经验,关于Splunk的索引和搜索的场景。
【主持丨大师兄】:好,谢谢羽嘉。看来针对搜索因为是一个比较大的话题,我们今后在下几期也可以考虑单独开一个关于搜索的话题。接下来我们请耿茂帮我们讲一下Pinterest的常规的一些做法。
【嘉宾丨耿茂】:那我简单介绍一下Pinterest的一些经验。我在加入Pinterest之前其实我是在Oracle、EMC、SuccessFactors这些公司,更多的是企业级软件和服务的公司里面做性能工程师。所以这些企业软件基本上就是三层架构,从Web服务器到应用服务器到数据库,当然也会有一些可扩展性的设计。比如说应用服务器无状态,然后可以动态扩容,数据库可以分库,可以Sharding。基本上的性能工作模式是比较容易找到每一个层次不同的压力测试点,会针对不同的特性我们可以去做不同的测试。外部服务器可能经常会出现的是网络连接的压力,或者是网络响应时间的压力。
应用服务器可能很多时候是java的,会有jvm的性能优化还有垃圾收集的调优。还有应用本身对于请求的处理状态,是线程模型呢,还是一个异步的网络I/O模型,这都会有不同。
像数据库的话可能更多的关注于数据的存储路径,比如说数据它的存储路径要合理地优化,设计的表结构足够合理,总是能够和快速地存取。这些经验可能是针对传统的企业软件基本上可以套用这一套规律。
但是我进入Pinterest之后就相当于是跨了一个行业,进入到面向用户的服务上。Pinterest现在主要是手机用户占了八成以上,另外还有两成是来自于网页。但背后都是使用我们的服务,几乎全在AWS之上。从架构上是有很大的不同,是说内部会有很多的微服务,和传统的企业软件不一样了。这些微服务我们在Pinterest里面可能有上百个。当然核心的几个服务,面向用户的几个服务大家会比较熟悉,我们SRE会接触的多一些,但是有好些服务我们也只知道个名字,并不清楚它内部是如何实现的。
所以作为一个运维工程师对于关心性能来说的时候,我们主要是要知道每一个服务的性能指标,比如说这个服务它能够接受多少个并发请求,它的50%的响应时间应该是多少,90%的响应时间应该是多少。所以,这里面有一个很重要的实践,针对所有的这些微服务,就是说每一个服务必须要定义一个SLA,叫做服务水平协议。比如说这个服务要达到比如说99.9%的可用性,它的90%的响应时间应该要在50毫秒以内,它能够响应的请求数每秒比如说是10万或者百万,这些就是这个服务要达到的目标。在一个新的服务被设计的时候首先要考虑这个目标,它的设计架构要能够支持到这个目标。所以在每个服务我们也有一个相应的Service Owner来负责这样一个服务的SLA。这是针对微服务上我感觉的一个重要的不同。
另外还有一个,因为有很多的服务,这些服务之间的依赖是很复杂的关系。有时候基本上就算是参与其中的工程师或者是架构师都不能够完全掌握清楚。所以这里面有很重要的是一个工具,怎么样把这个服务之间的依赖暴露出来。在Pinterest内部是有一个工具基于开源的软件叫Zipkin,来建立的。它的工作机制主要就是说在每个服务的客户端和服务端一起都会埋入一些代码,然后产生一个日志。这个日志会带有一个唯一的请求ID,或者叫做Span ID,这一个Span ID就是从用户的一个请求开始,一直记录他这个请求所流过的每一个服务,这每一个服务都会有这样的相同的ID。所以在很多不同的服务都产生日志之后,我们的日志抓取平台把这些搜集起来之后然后会有一些聚合处理,最后把处理的结果放到一个ElasticSearch的集群里面。最后我们可以通过一个叫做Pintrace,基于zipkin的一个网页UI然后来检查这样一个请求所经过的所有服务。然后通过汇聚很多的请求,我们可以得到一个服务之间的依赖图。然后这个依赖图里面我们可以知道这个服务与服务之间的请求流量大小。所以这对于我们知道这个系统的整个状况是很有用的一个工具。每一个服务在实现的时候都要遵循一定的规范,都要接入这样一个支持zipkin的日志的埋点。这是微服务的另外一方面。
除了Zipkin用作服务的请求响应时间的收集之外,还有一个很重要的东西,就是收集每一个服务它的性能指标。这里面性能指标可能是有基本的服务里面的每一个虚拟机的CPU使用率、内存使用率,它的网络的IO,块读写的IO,所有这些东西都会产生一些metrics,然后被集中到一个中心的监视系统。这样一个性能监视系统会搜集上百万个,甚至上千万个不同的metrics。然后在我们的每一个服务基本上都会定义一个dashboard, 然后可以实时地呈现这样一个服务的性能状况。
所以如果有问题的时候马上就会有page,报警到相应的服务的负责人。当然整个网站来讲的话,如果整个Site有问题,或者一些重要的路径有问题,就会先报警到SRE的平台,然后我们经过分析之后定位哪一个服务有问题,然后相应的肯定会有这个服务的负责人会被page到,然后这个服务的负责人会来解决这个问题。基本上这是我们运维的一个实践。
在平常还有关于性能的另外一个很重要的实践就是从公司上下对性能的指标都很在意。这是公司CEO制定的很重要的一个目标。他定义一个叫做性能目标的协议,然后发给所有的工程师。所以性能工作不是只是性能工程师或者SRE工程师的工作,而是所有人的目标。大家首先上线新的功能或者新的服务首先都要保证这样一个性能目标不会下降,比如用户的响应时间不会下降,用户体验不会下降。
相应的性能的调优工作有很多资深的工程师都一直在投入其中,他们会去仔细地检查,比如说我们使用的网络库,比如说我们用到一个库叫Finagle,它又用到Netty,在用到这些服务的响应时间在十个毫秒以内或者是更小,这样子他们对网络的连接的打开、关闭都非常敏感。所以有工程师会专门的去研究,然后去找到可以调优的地方,然后通过调整这样一些库,因为这些库是所有服务都用到的,所以在这样一个库的性能优化可以达到非常显著的性能调优效果。
所以基本上这是我的一些体会。
【主持丨大师兄】:谢谢耿茂,耿茂刚刚已经讲得非常详细了。因为在接下去的环节我们是准备了一些特定的关于性能的主题想和嘉宾一起采用互动的方式一起交流一下。其中有一块就是关于在分布式环境下的一个线上的性能检测,我想耿茂已经很好地回答了这个问题。
刚刚许多嘉宾也谈到了一个全链路的性能检测和性能测试的问题,因为我们知道性能指标更多的应该是反映一种业务指标,从一个用户的请求到拿到响应结果,它在什么情况下它能够支持多少个并发,在这些并发下要求的一个延时有多少,它其实是整个的一个端到端全链路的过程。
首先第一个问题,我想跟大家探讨一下,在条件允许的情况下,如果说我们要做性能测试,那我如何去模拟生产环境的测试。因为大家都知道,性能测试最关键的一点就是尽量要去模拟真实的一个线上的环境,包括数据和并发量,那你得到的整个的测试结果对你来说才是有参考价值的。我的第一个问题是大家觉得在模拟真正的一个线上环境上面,大家觉得有什么好的做法?还有一种观点就是可能根本我就没有办法真实地去模拟线上的情况,那我就是在线上直接去测了,有问题再直接调整。
关于这个问题我想听一下大家的看法,三位嘉宾有先想关于这个问题发表一下自己的意见吗?
【嘉宾丨王羽嘉】:好的。我们先说一下线上吧,因为Splunk这个产品其实它的特点就是我今天说的它很特别,它可以把非结构化的数据做索引和搜索。其实,用户在使用的时候,用户使用的任何的日志的信息其实默认都是可以走进到Splunk index里面去的,所以说对于线上的用户,比如说我们可以到他们的生产环境里面去,然后通过我们的Search,基本上是可以看到用户的行为的,比如他最近遇到了一个非常慢的search,那么我们可以看到他的search发生时间的时候,系统中具体的一些情况。比如说CPU的使用情况,以及系统中是不是有一些在后台job在工作,这些东西我们都可以看得很清楚。从这个角度来看,我们比较容易地帮他去定位一个问题。
【主持丨大师兄】:所以Splunk的做法是事先也没有办法真实地模拟在线上的环境,我就直接做一个基本的调优,然后让用户去线上跑,如果有问题的话我再真实地去查看线上的这样一个上下文环境,去定位问题,再告诉用户怎么去做一些优化。
【嘉宾丨王羽嘉】:对,这是一个非常challenge的行为。但是我们更多的总归还是要做性能的测试,性能测试的时候我们可能会想不管用户有没有问题,我们需要去了解到用户他们的使用的数据是什么样子的,这个情况其实我们的做法是当然我们肯定是通过我们的PM去跟用户那边看他们的数据量大概是多少,我们基本上是会了解一些指标,这些指标不包括他们比如说每天有多少的数据进来,然后每天他们进来的数据的数据的格式是什么样子的。因为进来的数据的格式可能是千奇百怪,可能我们要清楚。而且比如说有一些用户,像这个用户本身就是一个CDN的厂商,他肯定会进来很多的网络的数据,网络数据里面一旦被index的话会有一些比如说IP,source IP或者destination IP,这些都会进来。都会进来的话,它的数据值的变化量,比如它的IP的range大概有多少,其实对我们最终做search都会有很大的影响。所以像这些指标我们都要搞清楚,就是它数据的总量,以及数据在这个总量下面每一个字段的变化是有多少,是一千种、一万种还是十万种。然后我们根本他们给我们提供的指标,比如说我们会有一个内部的工具专门来生成这些数据的。我们把这些数据生成出来,生成在我们的测试环境里面去,然后我们来跑我们的测试,然后来评估我们的测试有没有达到我们最终的标准(criteria)。
【主持丨大师兄】:也就是说实际上整个的数据的分布情况是你们先会和客户做一个充分的沟通,然后利用一些沟通的结果,根据客户提的意见然后去模拟这部分数据,然后去做一个测试?
【嘉宾丨王羽嘉】:对的。
【主持丨大师兄】:那志超和耿茂关于这个有什么意见吗?因为可能Splunk是一个企业的产品,大家针对于互联网的产品的情况下觉得有没有可能也可以这样去做呢?
【嘉宾丨任志超】:实际上在我所经历的两家互联网的电商企业,蘑菇街和小红书来看,基本上你要在线下环境,就是在我们的测试环境里面去做线上的性能测试和调优是一个伪命题。我为什么这样说呢?事实上我在两家公司都经历了这种从没有做微服务,到微服务改造的过程。整个系统架构是处于一个在原来蘑菇街是一个统一,就是一个PHP的大的一个单服务的情况下,最后改成基于java的阿里的这一套整个的微服务体系。小红书是目前来说正在从python转向基于java的这种微服务。整个这样的一个分布式系统它的链路的调用规则和水位分布其实是在动态变化和调整过程中的。如果说我们强调全链路的性能测试或者说线上性能压力的能力,从某种意义上来说,你在线下很难搭建一个完整的分布式的这样一个模型来实时地模拟现在当前的系统架构的演进。
第二,就算有这样一个线下的测试环境。第一,它的一些相关依赖,比如我举一个例子,比如说redis,比如说存储,比如说MQ,这些第三方的依赖它的第一处理能力,它的SOI的水平和线上都是会有区别的。包括我们的数据的第二个大小,比如说我们到存储这一级别,小红书大部分还是用mongo,蘑菇街以前是mysql,那不同的存储集群对数据的响应和性能都是不一样的。而在一个自己数据中心的一个环境和你比如说用AWS或者腾讯云下面的这种云服务这样的一个封闭式的环境下面,它的性能场景也都是不一样的。所以在我的实践里面,我们通常来使用做性能的测试或者是做全链路的测试通常是基于以下三个方式。
第一,日志回放。我们通常做的是我们会在业务层面都会收集各种访问日志和你的使用日志。在一定的时间,我们通常说是半夜12点或者12点半以后等整个线上的业务下来以后,我们会隔离一些机器然后做线上白天的日志回放。
第二,我们写一部分的针对某一个单点写一些单点链路脚本,在夜里我们针对这个单点的压测脚本,同样把线上的服务做隔离以后对它进行压测。
第三,我们做影子库,做压测打标,我们会对所有的我们的压测链路加上我们的测试标这一层可以在线上进行,或者在我们的底层的业务中间层做处理。做了压测打标以后事实上也是在夜里12点以后通常来说我们会统一的对整个线上进行释压来去模拟真实的用户场景。
为什么我们说相对来说我们还是可以模拟出来比较真实的用户产品。第一,我们会先做几个事情。一是对历史的峰值的压力审阅的一个梳理。也就是说我们会对历史上比如上一次大促我们的模型是什么样子的。我举一个简单的场景,比如说有一万个用户同时进到我们的首页,其中六千个用户可能去访问了某个会场页,由会场页进到商详页里面可能大概并发量是在一千五,那这个时候下单的用户可能就是在五百,下单以后到支付可能是三百到一百五之间。所以基于这样的使用模型你可以基于我们的线上的这种当前架构下面的接口的调用链路,也就是刚才耿茂跟大家分享的,我们有一些工具可以把当前线上的这种链路调用关系以图形和链路的形式反映出来。基于这样一个链路调用关系我们可以援引出来压测的行为,所以基于这样的压测行为我们可以去开发全链路的压测脚本,而这个压测脚本是基于我们现在已有的单链路脚本之上开发和更新的。在这样的情况下我们可以约定在某一个时间,比如说开发、运维和测试的同学大家都在半夜12点以后我们同时开始对线上的链路进行集中的压测,那这个压测不是针对单点的,是针对全链路的。
在这样的情况下,加上我们的测试打标,可以把这些压力真实地打到我们的线上的系统,但是同时又不会产生比如说我们担心的,产生一些垃圾数据,是不是影响我们的业务数据,是不是影响我们线上的一些真实的体验。基于这样的压测打标以后我们可以从业务系统里面,可以从我们的线上服务里面把这些数据从最终的用户当中去掉。但是事实上我可以对线上的系统进行实时的真实的模拟。
这样的三种模式下我们可以针对某一个点,某一台机器,甚至某一个服务,和全链路进行有效的线上的压测。当然这一切都离不开整个团队的配合,也就是第一,我们要有足够好的监控手段,就是刚才耿茂说的,我们的APM,内部链路的关系,我们的Sentry,我们的业务的日志的收集,整个的运维的平台一定要具备。
第二,我们要具备全链路的施压的能力,施压能力提供通常来说如果用了其他的好的的情况下可以采用一些开源的现存工具,比如说用阿里的PTS,或者用自己写的基于Gatling这样一个用户式的调用施压链路。还有一些比如说像阿里内部有一些自己内部的一些压测工具,实在都没有了,可以直接用比如说AB、JMeter这样子的一些工具对单点进行。但是通过一些链路的调用等一些引擎,可以把这些施压点串起来对整个系统构成压力行为的施压,这样才能够对整个线上的系统是有价值的压力测试的场景。
这是我们这边实践的一些经验。
【主持丨大师兄】:非常感谢。那耿茂,你关于这点有什么向说的吗?
【嘉宾丨任志超】:志超刚才说的很好,他们的压测做得很不错。相比较而言,Pinterest说实话我们就是在线上测,就没有自己生成数据来做压力测试这种东西。这里面有几个原因,一个是我们用AWS,是一个弹性的云计算的环境,我们的这些微服务基本上都是动态伸缩的。所以它在请求量大的时候基本上是可以水平扩展,可以去支持它的请求。所以如果我们测试的时候,那相应的服务也会自动扩容去支撑这样一个流量。只要AWS没有出现问题,没有自动扩容的能力受影响的话,一般不会有大的问题。当然,有一些存储的服务他们基于MySQL,或者基于HBase,是需要做预先的切分的,不能够动态扩容的。这种可能是先基于我们实际的流量测试之后他们会有一个相应的准备。比如说会先划分成多少个数据库,产生数据库也可能在应对流量增长的时候预先做容量升级,从一个低CPU或者内存的服务器动态升级到高级的上面,在不影响服务的情况下。这是AWS这个环境给我们的一个能力,所以基本上每个服务都会考虑在线升级、在线扩容的办法。
我们还有一个,如果有功能的变化或者是一些性能改进的话我们通常是做AB测试。同样一个服务可能有不同的环境,有A环境和B环境,一部分机器是A环境,一部分是B环境,你收集相应的性能指标之后做一个比较,然后发现确实是有进步,那我们把它全部切换到你的优化上面。如果说性能不是你预想的那样,那再回滚回来。所以一切都是通过动态的调整服务的集群来实现的。
另外,我们当然也有测试,这就是每个服务自己的事情了。在通常做一些技术选型的时候会做足够的测试,不管是MySQL也好,HBase也好,或者是其他用到的一些ElasticSearch、Redis这样的一些通用的开源技术,那就是会用相应的测试工具,如果有开源的拿开源的来用,如果没有会自己写一写。然后来有针对性的针对这个服务的使用场景来测试这个基础的技术的扩展性。还有在AWS上我们会有一些测试,关于比如说EC2虚拟机类型的性能测试,我们会测试它的新一代的虚拟机比如说I3, r4, c5这些不同的虚拟机的性能表现,以此来决定我们是不是可以升级换代一些。或者说从CPU优化的服务器换到存储优化的服务器,会做一些这样的测试,有针对性的。还有是因为这些跟操作系统的版本和Kernel也有关系,所以有很多测试也会针对不同的Kernel来看。因为那个影响其实还不小,但是所有这些测试一定是每个服务单独来看,然后逐渐的AB测试,然后逐渐的扩展到整个系统里去。所以,有些升级变化会花很长的时间。
【主持丨大师兄】:谢谢,我接下去有个问题,实际上刚刚你们在讲的是关于动态扩容的问题,那有没有可能有一种情况,因为有些问题可能是架构上,或者是代码上的一些问题,导致我可能前期没有测出来,但真的等到线上环境以后,它不是靠扩容就可以解决的,那我只根据java的话可能比如说会有Memory Leak,那等到你线上环境达到一定的量的时候出现了Memory Leak,那这种情况一般是扩容解决不了,因为你扩一下机器它马上就被消耗光了,一般出现这种情况的话我们应该怎么样去做一些线上的应对或者隔离?
【嘉宾丨耿茂】:在Pinterest的做法也是会有一个叫做rate limiter的东西,你可以限容。这个rate limiter其实就是在客户的一些库然后java语言或者python语言这种,这个库就是各种客户端的语言都支持的,所以在客户端调用的时候会受到rate limiter的限制,如果在后端的服务支撑不了动态扩容,不能够支持流量增长的事实那就会限容这样子。
【主持丨大师兄】:那如果发生这种情况的话,这个服务本身是有问题了,是打算把它隔离掉,还是接下去会怎么处理?
【嘉宾丨耿茂】:这个之后再处理,先扛住,不让它彻底当掉。就是限制上游来的流量,让这个等于就是降级,所以只使用这部分服务的人受到一些影响。或者说,超过了一定量的用户受到影响,但是基本上这个服务还是暂时可用的,当然这个服务的负责人一定会想办法怎么样把它尽快扩容,然后能够支撑,能够解除这样一个流量限制。
【嘉宾丨任志超】:这边我们也可以分享一下在电商这块我们的一些做法。通常来说作为电商来说最大的心理压力就是平时一般都没有什么流量,正常的用迭代、发布,然后线上一般都不会有太大的问题。最大的问题其实就是来自于这种像大促期间流量基本上是十倍以上的增长,这种情况下我们一般来说正规的做法是第一,我们会定预期水位,第二会定开关、降级预案,第三会对降级预案进行分解。对于降级预案进行分解会通过一些敏感服务,核心电路会产生什么样子的降级做一个定义,可能会降级会有一些降级开关,它也会有一些触发条件,以及在这个触发条件下面相关的操作。那这些操作一些是通过动态熔断,比如我曾经做熔断,另一些就是通过业务熔断来做的。比如说我们把这个业务直接从前台下掉了。第三个是我们可以在前台统一做一些所谓的批量化,比如说把一些高并发的请求。
我们曾经在蘑菇街做过这样一个产品,就是在所有的客户端的相应过程中加上一层,当他在大促时间,大促时我们把两个开关开了以后,当客户端提交这个请求,发现我们我们的返回值是某个制定的开关结果的时候,它会把所有的对后端的请求做缓存,于是我在接下来15秒钟之内我不会对后台发任何请求,对前台会造成一个Loading的标识,对于客户来说感觉是慢了,但是事实上我们还是在有机会完成交易。另一方面,对于一些可降级的,比如说前端的一些页面。
比如举个例子,我们商详页,我们会对它若干个区域,比如一些核心区域,价格肯定是不能错的,我们的下单功能肯定是不能少的,除此之外我们都是可以降级,在大促期间我们有一个降级预案,当到这个水平的时候我们会把商详页上的相关商品和相关笔记我们再下掉。在这个时候当我们降级被触发以后在客户端看到的页面会只有标准的商详和里面的价格本身,以及一个下单的按钮,其他的额外的东西一切都没有了。这是正常的情况下的降级和熔断。
但是就像你说的,总会有没有测到的情况。比如我们出现过在大促前前一天刚上的一个业务,这个业务刚好是过了我们全链路压测的场景以后上去的。而这个业务就有一个while true的循环就锁住我们的数据库,而当时确实就上去了,这个时候又没有降级预案。那我们的方法,第一,先定位到问题所在。发现当有这个问题,我们整个数据库锁死,整个线上没有反应的时候,我们第一是回滚,因为基于我们的线上的性能监控我们可以知道是哪个服务出了问题。首先对这个服务进行暂时的线上的回滚,紧急回滚以后先定位到问题,定位到问题以后重新把开关设好,并且开开,在这种情况下几个手段我们通常来说是并行开展的。就是降级、扩容,以及线上的紧急回滚和修复,整个是一个执行体系,和系统架构,和我们的技术领域其实也没有太大的关系,在任何其它领域都可以做类似的操作。
【主持丨大师兄】:谢谢。我这边接下去的问题刚刚都有说了,就是整个系统的话不仅仅是Performance团队或者是测试团队的事,而是和开发,和运维,和架构都相关。
我的一个问题是说可能在你不考虑性能的情况下,那我上的功能肯定决定是很快的,开发的话我就按功能开发完就没事了。但是如果涉及到我这边性能方面是有些要求,有些架构,就像各位刚刚介绍的一样。首先要有一些微服务的监测,我每上一个功能是要有可监测的,我可能还会去准备一些降级的预案做一些隔离,那我要考虑到这些架构的方方面面的时候,那我怎么同时能够保证我的开发上的敏捷度,或者怎么样去和真正的业务上的开发比较好的做一个协同呢?
【嘉宾丨任志超】:从我们这边的实践来看说实话这是一个不断教育的过程,可能因为我待的公司都比较特殊,都处在一个快速扩张的时间,进云的速度是相当快。比如我们一个业务可能在半年的时间里面可能翻一翻,两三翻 ,里面的性能对于一些老同学来说它对限容架构和当前的服务有些什么问题他是很清楚的,在这样一种状态下还是比较容易去做协同和扩展的。
但是,当然不断的有新同学来,团队在不断的扩充,新业务在不断的增加的过程中其实很难有一个合适的途径对他进行一个教育。更多的是,第一,树立一个Ramp up Plan的时候,我们可能需要对他性能方面的专项的一个Enablement,就是让他能够知道我所负责的这块业务当前的一个性能模型是什么意义,架构是什么意义,以前有什么坑,那这些坑我们当时又怎么解决的。
另外一点,对于整个公司来说通常我们都会有一个相对于底层的虚拟团队也好,还是一个基础团队也好,会负责对一些就像刚刚耿茂说的,对一些中间层,对一些公共库我们要做一些规范和标准化。比如说我们会要求所有的目前来说所有的微服务中间层都采用Thrift协议,都采用长链让我们的服务寻址和路由都用我们自己封装好的REDRPC这一套。通过这样一些分层和公共组件的隔离,我们可以把一些和性能相关的一些东西从这个里面抽象出来,抽离出来,这样对于业务开发的时候可以更关注在业务本身。
第三点,目前来说大部分互联网公司都在做前后端分离,那做了前后端分离以后对于业务的同学通常来说会换成两种不同的东西,第一种我聚焦在后端的接口开发,同时前端的同学会对UI展现和交互进行一些设计,然后在这个设计过程中通过和产品的紧密配合大概知道从业务的层面怎么去优化交互的性能,有很多东西其实可以在前端的层面去做的,比如我们的一些CDN,我们一些回源,我们的一些接口的优化,实际上是和整个业务开发的同学是可以做隔离的。
有了这些关键的做法以后,另外一点就是一个定期了,因为对于电商来说定期的月促,每年至少有两次或者三次或者更多的大促,借助这样的机会我们会对它进行几轮的这种全链路的压测和定期的单链路的压测,其实就相当于在持续的更新和迭代的过程。通过这样的过程教育新来的同学让他慢慢地成长起来。其实没有什么所谓的Silver bullet这种银弹,更多的还是执行力的过程。
【主持丨大师兄】:非常感谢。我相信可能大部分公司也都是这么做的,接下来我们时间差不多了,我这边就留一些时间给一些听众,看看他们有什么问题,或者大家有问题的话可以在群里面提出来,让嘉宾帮忙解答一下。
【嘉宾丨耿茂】:我看到余侃有一个问题是关于Docker对吧?我正好可以想讲一下,这也是在Pinterest我一进去就开始做的事情。之前Pinterest的部署主要是基于Puppet,有很多的问题。因为Puppet在动态更新环境的时候可能会遇到一些意想不到的问题,好像依赖的包会有问题,或者其他的东西,引起部署失败。后面引入Docker之后一切通过Docker Image去部署的话,那就一切好了很多。用Puppet这是历史原因,以前是这么搞的。现在替换成为Docker之后这个部署就相应地稳定很多,但是不是所有的服务都被Dockerized的,只是还在一个迁移的过程当中。至于Kubernetes和Mesos这块现在Pinterest还没有大规模使用,Mesos我们用在数据处理平台上。像现在AWS autoscaling 再加上Docker Image这种方式,其实可以做到动态的发布回滚,挺方便的。
【主持丨大师兄】:我看到有一个人在问怎么做性能相关的OKR或者KPI设计。我相信三位嘉宾当中可能Pinterest和Splunk的做法应该是会比较相似,可能小红书又是不同的做法,我想请各位嘉宾分别讲一下吧。
【嘉宾丨任志超】:对于我来说我最大的OKR就是保证大促的稳定,这个里面我们做设定的时候其实很简单,因为大促通常来说就那一波过来我们能够稳定地保证它平稳地通过,所谓的平稳通过就是说我们全站,那核心的业务比如说我们的下单支付,我们的商详,我们的会场是可以打开的。其实就和你在淘宝一样,比如说你在双十一去下单的时候,你下下去以后会不会全站都下不了单,碰到这种情况肯定你的KPI要挂了。我现在目前来说我对这块更多的是保障在大促高峰的时候能够下单和支付和商详页这三个主链路不要出问题。
【主持丨大师兄】:所以志超你这边更多的还是比较偏业务的保证功能正常的指标吧。
【嘉宾丨任志超】:对,线上的。
【主持丨大师兄】:我想另外两位嘉宾你们是不是会有更加关于请求的吞吐量和延时的指标呢?会有这些KPI吗?
【嘉宾丨耿茂】:是,我们在Pinterest SRE其实就是负责这个整个网页和面向手机客户端的API的吞吐量和Success Rate。三个九的Success Rate是必须的。然后响应时间要在几百毫秒以内,如果有低了之后马上就会有报警告诉我们。
【主持丨大师兄】:这个指标是谁定的呢?是基于一个什么样的场景会定一个具体的量化指标?
【嘉宾丨耿茂】:这还是根据业务来的。像我们的外部主页其实有很多不同的路径,像有的路径是Create一个Pin,有的路径是做一个搜索,有的路径是直接看我们的Home Feed,有的路径是看Related Pin。所以每一个路径其实会有相应的团队在背后,他们要背相应的指标的,比如Success Rate和响应时间。这是面向用户使用场景的一个事情。
【嘉宾丨王羽嘉】:我稍微补充一点,对于Splunk来说可能第一指标是数据每天被index的数据量是多少,因为这个对于客户来说,比如说它在客户的生产环境里,或者他自己的IT环境里面可能每天的产生的数据量就是非常庞大的,他确实是可以会比较合理地说,我为了这些数据至少要在几个小时之内都要被index进来,他对这个一天或者一个小时index的capability是非常在意的。一般来说我们会保证一天两个TB的数据或者更多,这个是一个必备的指标。
【主持丨大师兄】:关于端到端的Tracking ID耿茂已经回答了, Zipkin是目前比较流行的分布式的监测方案。
接下来最后一个问题,有一位同学问了一下开发过程中单用户的性能和并发测试的实践,这个问题应该是更多在于普通的Developer在开发过程中如何对于Performance有敏锐的Insight,并付诸于实践,写出对于Performance友好的代码。这个我不知道各位有对各自的一些Developer有这方面的一些要求吗?
【嘉宾丨耿茂】:这个我说一下,像现在单用户的测试在微服务的环境下是比较难做的,主要还是通过trace,就是如果有一个请求进来,然后你可以trace到所有经过的服务,每个服务的响应时间都在这样一个span里面可以体现出来,那你就很容易定位到问题在哪里,可以去优化。
【主持丨大师兄】:所以你的建议还是在初期教育的时候尽量去让他们用一些比较通用的,特别是占用外部资源的时候,可能就是占用一些公用的一些内库,就是保证基本的性能不会差到哪里去,可能真正的测试还是要到一个线上的环境评估一下这方面的性能?
【嘉宾丨耿茂】:对,我想其实最重要的就是你先埋入一些可测量的点,如果能够收集到这些实际的数据相应地来做性能调优,那就很有针对性,而且就可以省掉很多时间。当然你要埋入这些监视的东西需要花工夫,但是你做了以后会有很大的好处。
【嘉宾丨任志超】:我也同意耿茂的,不过我们这边通常来说会在整个上线流程都会分为几个不同的阶段,在开发的T环境下,通常来说他们会做本身开发追求的本身的功能测试。但是到了我们SIT集成环境以后其实相关的一些依赖,目前来说是有的。我们的测试过程中会保证在有线上数据同步过来的情况下会有些业务点在正常的处理模型下单用户是OK的,也就是说我们会在SIT的环境下对单用户的性能做一些监测,这个监测包括响应时间等等。
等到C环境,就是我们用线上的数据然后更新我们服务代码式的单独的开发代码的情况下,我们就可以对线上的依赖进行一些基本的校验。耿茂说的,我们还有AB,AB上去的时候流量不是说一下子全打过来的,可能是通过灰度不断地拉过来的,那在拉过来的过程中一旦发现问题,可以再回滚,整个的过程中我们的节奏里面会相对来说有效的保障,如果真的有代码问题,在针对上线以前我们还是有几道关口可以卡的,再加上耿茂刚刚说的链路的应用监控,也可以从这个角度来有效的保障。
【主持丨大师兄】:你们觉得内部监控,因为本身它也有性能方面的Overhead,你们觉得这方面是比如现在一些开发的框架已经优化得不错,还是说再做埋点和Tracking的时候需要充分分析Overhead对于Production的影响。
【嘉宾丨耿茂】:我的看法是开源的已经做得很不错了,但是自己还是要注意,因为埋点是有Overhead的,如果你在一个循环里面,比如说是一个很critical的code path里面去做这些东西可能会影响到这个服务反而没有起到监控的效果了,这个是通过灰度上线、AB上线的方式来及早发现,及早回滚,避免出现真正的问题。
【主持丨大师兄】:好,谢谢耿茂。我们今天这期节目如果大家没什么问题的话就到这里,我们下期再见。谢谢三位嘉宾。
“跨境茶话会”是由移动增长技术服务商“魔窗”联合国内外众多技术专家发起的在线技术交流活动,目前已邀请嘉宾来自Google、ebay、Snap、Uber、VISA、Pinterest、BranchMeteics、Splunk、小红书、华为等国际知名IT企业在职高级工程师,面向所有互联网从业技术人员分享交流先进理念和实战案例,同时为中美技术朋友提供跨境交友和深度学习的平台。
“跨境茶话会”结合前沿热点技术话题,精心策划每月一个线上技术主题交流,每期邀请来自国内外互联网界的三位实战嘉宾分享一线技术最佳实践,并针对核心技术问题对话答疑,为技术从业者拓宽思路、提升技术实力、驱动业务增长。
下期免费报名:https://www.wenjuan.net/s/3iu...