转载链接:https://kb.cnblogs.com/page/565901/
1、业务架构:从单体式到微做事K歌亭是唱吧的一条新业务线,旨在供应线下便捷的快餐式K歌办法,用户可以在一个电话亭大小的空间里完成K歌体验。K歌亭在客户端有VOD、微信和Web共三个交互入口,业务繁芜度较高,如长连接池做事、用户系统做事、商户系统、增量更新做事、ERP等。对付做事真个稳定性哀求也很高,由于K歌亭摆放地点不固定,很多场所的运营活动会造成突发流量。
为了快速开拓上线,K歌亭项目最初采取的是传统的单体式架构,但是随着韶光的推移,需求的迭代速率变得很快,代码冗余变多,常常会涌现牵一发动全身的改动。重构不但会花费大量的韶光,而且对运维和稳定性也会造成很大的压力;此外,代码的耦合度高,新人上手较困难,每每须要通读大量代码才不会踩进坑里。

鉴于上述弊端,我们决定接下来的版本里采取微做事的架构模型。从单体式构造转向微做事架构中会持续碰到做事边界划分的问题:比如,我们有user做事来供应用户的根本信息,那么用户的头像和图片等是该当单独划分为一个新的service更好还是该当合并到user做事里呢?如果做事的粒度划分的过粗,那就回到了单体式的老路;如果过细,那做事间调用的开销就变得不可忽略了,管理难度也会指数级增加。目前为止还没有一个可以称之为做事边界划分的标准,只能根据不同的业务系统加以调节,目前K歌亭拆分的大原则是当一块业务不依赖或极少依赖其它做事,有独立的业务语义,为超过2个的其他做事或客户端供应数据,那么它就该当被拆分成一个独立的做事模块。
在采取了微做事架构之后,我们就可以动态调节做事的资源分配从而应对压力、做事自治、可独立支配、做事间解耦。开拓职员可以自由选择自己开拓做事的措辞和存储构造等,目前整体上利用PHP做根本的Web做事和接口层,利用Go措辞来做长连接池等其他核心做事,做事间采取thrift来做RPC交互。
2、系统架构的构思与解读2.1 容器编排
唱吧K歌亭的微做事架构采取了Mesos和Marathon作为容器编排的工具。在我们选型初期的时候还有三个其他选择,Kubernetes、 Swarm、 DC/OS:
DC/OS:作为Mesosphere公司的拳头产品,基本上是希望一统天下的节奏。以是组件很多,功能也很全面。但是对付我们在进行微做事架构初期,功能过于弘大,学习本钱比较高,后期的生产环境掩护压力也比较大。Swarm:Docker公司自己做的容器编排工具,当时理解到100个以上物理节点会有无相应的情形,对付稳定性有一些担忧。Kubernetes:Google开源的的容器编排工具,在选型初期还没有很多公司利用的案例,同时也听到了很多关于稳定性的声音,以是没有考虑。但是在全体2016年,越来越多的公司开始在线上利用Kubernetes,其稳定性逐步提高,如果再选型该当也是个好选择。Mesos:由于理解到Twitter已经把Mesos用于生产环境,并且觉得架构和功能也相对大略,以是末了选择了Mesos+Marathon作为容器编排的工具。2.2 做事创造
我们采取了etcd作为做事创造的组件,etcd是一个高可用的分布式环境下的 key/value 存储做事。在etcd中,存储因此树形构造来实现的,非叶结点定义为文件夹,叶结点则是文件。我们约定每个做事的根路径为/v2/keys/service/$service_name/,每个做事实例的实际地址则存储于以做事实例的uuid为文件名的文件中,比如账户做事account service当前启动了3个可以实例,那么它在etcd中的表现形式则如下图:
当一个做事实例向etcd写入地址成功时我们就可以认为当前做事实例已经注册成功,那么当这个做事实例由于各类缘故原由down掉了之后,做事地址自然也须要失落效,那么在etcd中要如何实现呢?
把稳,图中的每个文件有一个ttl值,单位是秒,当ttl的值为0时对应的文件将会被etcd自动删除。当每个做事实例启动之后第一次注册时会把存活韶光即ttl值初始化为10s,然后每隔一段韶光去刷新ttl,用来像向etcd申报请示自己的存活,比如7s,在这种情形下基本上可以担保做事有效性的更新的及时性。如果在一个ttl内做事down掉了,则会有10s钟的韶光是做事地址有效;而做事本身不可用,这就须要做事的调用方做相应的处理,比如重试或这选择其它做事实例地址。
我们做事创造的机制是每个做事自注册,即每个做事启动的时候先得到宿主机器上面的空闲端口;然后随机一个或多个给自己并监听,当做事启动完毕时开始向etcd集群注书籍身的做事地址,而做事的利用者则从etcd中获取所需做事的所有可用地址,从而实现做事创造。
同时,我们这样的机制也为容器以HOST的网络模式启动供应了担保。由于BRIDGE模式确实对付网络的损耗太大,在最开始就被我们反对了,采取了HOST模式之后网络方面的影响确实不是很大。
2.3 监控,日志与报警
我们选择Prometheus汇总监控数据,用ElasticSearch汇总日志,紧张的缘故原由有:
生态相对成熟,干系文档很全面,从通用的到专用的各种exporter也很丰富。查询语句和配置大略易上手。原生具有分布式属性。所有组件都可以支配在Docker容器内。Mesos Exporter,是Prometheus开源的项目,可以用来网络容器的各项运行指标。我们紧张利用了对付Docker容器的监控这部分功能,针对每个做事启动的容器数量,每个宿主机上启动的容器数量,每个容器的CPU、内存、网络IO、磁盘IO等。并且本身他花费的资源也很少,每个容器分配0.2CPU,128MB内存也毫无压力。
在选择Mesos Exporter之前,我们也考虑过利用cAdvisor。cAdvisor是一个Google开源的项目,跟Mesos Exporter网络的信息八成以上都是类似的;而且也可以通过image字段也可以变相实现关联做事与容器,只是Mesos exporter里面的source字段可以直接关联到marathon的application id,更加直不雅观一些。同时cAdvisor还可以统计一些自定义事宜,而我们更多的用日志去网络类似数据,再加上Mesos Exporter也可以统计一些Mesos本身的指标,比如已分配和未分配的资源,以是我们终极选择了Mesos Exporter。
如下图,便是我们监控的部分容器干系指标在Grafana上面的展示:
Node exporter,是Prometheus开源的项目,用来网络物理机器上面的各项指标。之前一贯利用Zabbix来监控物理机器的各项指标,这次利用NodeExporter+Prometheus紧张是出于效率和对付容器生态的支持两方面考虑。时序数据库在监控数据的存储和查询的效率方面较关系数据库的上风确实非常明显,详细展示在Grafana上面如下图:
Filebeat是用来更换Logstash-forwarder的日志网络组件,可以网络宿主机上面的各种日志。我们所有的做事都会挂载宿主机确当地路径,每个做事容器的会把自己的GUID写入日志来区分来源。日志经由ElasticSearch汇总之后,聚合的Dashboard我们统一都会放在Grafana上面,详细排查线上问题的时候,会用Kibana去查看日志。
Prometheus配置好了报警之后可以通过AlertManager发送,但是对付报警的聚合的支持还是很弱的。不才一阶段我们会引入一些Message Queue来自己的报警系统,加强对付报警的聚合和处理。
ElastAlert是Yelp的一个Python开源项目,紧张的功能是定时轮询ElasticSearch的API来创造是否达到报警的临界值,它的一个特色是预定义了各种报警的类型,比如frequency、change、flatline、cardinality等,非常灵巧,也节省了我们很多二次开拓的本钱。
2.4 事务追踪系统——KTrace
对付一套微做事的系统构造来说,最大的难点并不是实际业务代码的编写,而是做事的监控和调试以及容器的编排。微做事相对付其他分布式架构的设计来说会把做事的粒度拆到更小,一次要求的路径层级会比其他构造更深,同一个做事的实例支配很分散,当涌现了性能瓶颈或者bug时如何第一韶光定位问题所在的节点极为主要,以是对付微做事来说,完善的trace机制是系统的核心之一。
目前很多厂商利用的trace都是参考2010年Google揭橥的一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》来实现的,个中最著名确当属twitter的zipkin,海内的如淘宝的eagle eye。由于用户规模量级的逐年提升,分布式设计的系统理念越来越为各厂商所接管,于是出身了trace的一个实现标准opentracing ,opentracing标准目前支持Go、JavaScript、Java、 Python、Objective-C、C++六种措辞。 由sourcegraph开源的appdash是一款轻量级的,支持opentracing标准的开源trace组件,利用Go措辞开拓K歌亭目前对appdash进行了二次开拓,并将其作为其后端trace做事(下文直接将其称之为Ktrace),紧张缘故原由是appdash足够轻量,修正起来比较随意马虎。唱吧K歌亭业务的胶水层利用PHP来实现,appdash供应了对protobuf的支持,这样只须要我们自己在PHP层实现middleware即可。
在trace系统中有如下几个观点
(1)Annotation
一个annotation是用来即时的记录一个事宜的发生,以下是一系列预定义的用来记录一次要求开始和结束的核心annotation
cs - Client Start。 客户端发起一次要求时记录sr - Server Receive。 做事器收到要求并开始处理,sr和cs的差值便是网络延时和时钟偏差ss - Server Send: 做事器完成处理并返回给客户端,ss和sr的差值便是实际的处理时长cr - Client Receive: 客户端收到回答时建立。 标志着一个span的结束。我们常日认为一但cr被记录了,一个RPC调用也就完成了。其他的annotation则在全体要求的生命周期里建立以记录更多的信息 。
(2)Span
由特定RPC的一系列annotation构成Span序列,span记录了很多特定信息如 traceId, spandId, parentId和RPC name。
Span常日都很小,例如序列化后的span常日都是kb级别或者更小。 如果span超过了kb量级那就会有很多其他的问题,比如超过了kafka的单条大小限定(1M)。 就算你提高kafka的大小限定,过大的span也会增大开销,降落trace系统的可用性。 因此,只存储那些能表示系统行为的信息即可。
(3)Trace
一个trace中所有的span都共享一个根span,trace便是一个拥有共同traceid的span的凑集,所有的span按照spanid和父spanid来整合成树形,从而展现一次要求的调用链。
目前每次要求由PHP端天生traceid,并将span写入Ktrace,沿调用链通报traceid,每个service自己在有须要的地方埋点并写入Ktrace。举例如下图:
每个色块是一个span,表明了实际的实行韶光,常日的调用层级不会超过10,点击span则会看到每个span里的annotation记录的很多附加信息,比如做事实例所在的物理机的IP和端口等,trace系统的花费一样平常不会对系统的表现影响太大,常日情形下可以忽略,但是当QPS很高时trace的开销就要加以考量,常日会调度采样率或者利用行列步队等来异步处理。不过,异步处理会影响trace记录的实时性,须要针对不同业务加以取舍。
目前K歌亭在生产环境里的QPS不超过1k,以是大部分的记录是直接写到ktrace里的,只有歌曲搜索做事考试测验性的写在kafka里,由mqcollector网络并记录,ktrace的存储目前只支持MySQL。一个好的trace设计可以极快的帮你定位问题,判断系统的瓶颈所在。
2.5 自动扩容
在做事访问峰值的涌现时,每每须要临时扩容来应对更多的要求。除了手动通过Marathon增加容器数量之外,我们也设计实现了一套自动扩缩容的系统来应对。我们扩缩容的触发机制很直接,根据各个做事的QPS、CPU占用、内存占用这三个指标来衡量,如果三个指标有两个指标达到,即启动自动扩容。我们的自动扩容系统包括3个模块:
Scout:用于从各个数据源取得自动扩容所须要的数据。由于我们的日志全部都汇总在ElasticSearch里面,容器的运行指标都汇总到Prometheus里面,以是我们的自动扩容系统会定时的要求二者的API,得到每个做事的实时QPS、CPU和内存信息,然后送给Headquarter。Headquarter:用于数据的处理和是否触发扩缩容的判断。把从Scout收到的各项数据与本地预先定义好的规则进行比对,如果有两个指标超过定义好的规则,则关照到Signalman模块。Signalman:用于调用各个下贱组件实行详细扩缩容的动作。目前我们只会调用Marathon的/v2/apps/{app_id}接口,去完成对应做事的扩容。由于我们的做事在容器启动之后会自己向etcd注册,以是查询完容器状态之后,扩缩容的任务就完成了。3、基于Mesos+Marathon的CI/CD
3.1 持续集成与容器调度
在唱吧,我们利用Jenkins作为持续集成的工具。紧张缘故原由是我们想在自己的机房掩护持续集成的后端,以是放弃了Travis之类的系统。
在履行持续集成的事情过程中,我们碰到了下列问题:
Jenkins Master的管理问题。多个团队共享一个Master,会导致权限管理困难,配置改动、升级门槛很高,Job创建和修正有很多规则;每个团队用自己的Master,会导致各个Master之间的插件、更新、环境掩护有很多的重复事情。Jenkins Slave 资源分配不平均:忙时Jenkins slave数量不敷,Job运行须要排队;闲时Jenkins Slave又涌现空闲,非常摧残浪费蹂躏资源。Jenkins job运行须要的环境多种多样,比如我们就有PHP,java,maven,Go,python等多种编译运行环境,搭建和掩护slave非常费时。多个开拓职员的同时提交,各自的代码放到各自独立的测试环境进行测试。基于以上问题,我们选择利用Mesos和Marathon来管理Jenkins集群,把Jenkins Master和Jenkins Slave都放到Docker容器里面,可以非常有效的办理以上问题。根本架构如下图:
不同开拓团队之间利用不同的Jenkins Master。把公用的权限、升级、配置和插件更新到私有Jenkins Master镜像里面,推到私有镜像仓库,然后通过Marathon支配新的Master镜像,新团队拿到的Jenkins Master就预安装好了各种插件,各个现有团队可以无缝吸收到整体Jenkins的升级。各种不同环境的Jenkins Slave,做成Slave镜像。按照须要,可以通过Swarm Plugin自动注册到Jenkins master,从而组织成slave pool的形式;也可以每个job自己去启动自己的容器,然后在容器里面去实行任务。Jenkins job从容器调度的角度分成两类,如下图:环境敏感型:比如编译任务,须要每次编译的环境完备干净,我们会从镜像仓库拉取一个全新的镜像启动容器,去实行Job,然后再Job实行完成之后关闭容器。韶光敏感型:比如实行测试的Job,须要尽快得到测试结果,但是测试机器的环境对付测试结果没什么影响,我们就会从已经启动好的Slave Pool里面去拉取一个空闲的Slave去实行Job。然后再根据Slave被利用的频率去动态的扩缩容Slave pool的大小就好了。
3.2 CI/CD流程
基于上述的根本架构,我们定义了我们自己的持续集成与持续交付的流程。个中除了大规模利用Jenkins与一些自定制的Jenkins插件之外,我们也自己研发了自己的支配系统——HAWAII。
在HAWAII中可以很直不雅观的查看各个做事与模块的持续集成结果,包括最新的版本,SCM revision,测试结果等信息,然后选择相应的版本去支配生产环境。
在支配之前,可以查看详细的测试结果和与线上版本的差异,以及上线过程中的各个步骤运行的状态。
基于上述根本架构,我们的CI/CD流程如下:
SVN或者GIT收到新的代码提交之后,会通过hook启动相应的Jenkins job,触发全体CI流程。Jenkins从私有镜像仓库拉取相对应的编译环境,完成代码的编译。Jenkins从私有镜像仓库拉取相对应的运行时环境,把上一步编译好的产品包打到镜像里面,并天生一个新版本的产品镜像。产品镜像是终极可以支配到线上环境的镜像,该镜像的metadata也会被提交到支配系统HAWAII,包括GUID,SCM revision,Committer,韶光戳等信息将步骤3中天生的产品镜像支配到Alpha环境(该环境紧张用于自动化回归测试,实际启动的容器实在是一个完全环境,包括数据容器,依赖的做事等)。Jenkins从私有镜像仓库拉取相对应的UT和FT的测试机镜像,进行测试。测试完成之后,会销毁Alpha环境和所有的测试机容器,测试结果会保存到支配系统HAWAII,并会邮件关照到干系职员。如果测试通过,会将第3步天生的产品镜像支配到QA环境,进行一系列更大范围的回归测试和集成测试。测试结果也会记录到HAWAII,有测试不通过的地方会从第1步从头开始迭代。全部测试通过后,就开始利用HAWAII把步骤3中天生的产品镜像支配到线上环境。小结
随着互联网的高速发展,各个公司都面临着巨大的产品迭代压力,如何更快的发布高质量的产品,也是每个互联网公司都面临的问题。在这个大趋势下,微做事与DevOps的观点应运而生,在低耦合的同时实现高聚合,也对新时期的DevOps提出了更高的技能与理念哀求。
这也是我们公司在这个新的业务线上面进行,进行考试测验的紧张缘故原由之一。对付微做事、容器编排、虚拟化、DevOps这些领域,我们一步一步经历了从无到有的过程,以是很多方面都是本着从知足业务的目标来只管即便严谨的开展,包括所有的做事与根本架构都进行了高并发且永劫光的压力测试。
不才一步的事情中,我们也有几个核心研究的方向与目标,也希望能跟大家一起学习与磋商:
完善做事降级机制完善报警机制完善负载均衡机制