微服务架构实践 - 你只懂docker与spring boot就够了吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微服务架构实践 - 你只懂docker与spring boot就够了吗?相关的知识,希望对你有一定的参考价值。
参考技术A
背景
随着公司一年多的成长,我们已经开发了数十个项目了,后台有JAVA的有php的,为了更好地提升开发与管理效率,各技术大牛小牛们时常进行激烈的PK,碰撞出了许许多多爱的火花,比如其中之一:微服务实践
设计
只需要有一套BASE微服务,BASE微服务生成业务系统微服务实例,供各个业务系统调用;业务系统不直接调用BASE,只能调用微服务INSTANCE。
这是运维的问题,让运维去解决,运维使用工具,实际也不算困难,反正执行的都是脚本,不需要手工操作。
单点故障影响全局,我们选择了稳定更重要;另外saas的话,为了应对不同行业,会存在过度设计的嫌疑;私有化更容易。
调用逻辑
设计理念
非模块化,谈不上微服务,比如我们上面的用户微服务、产品微服务、地址微服务等,都需要先模块化,为了更好地落实开发,你可能不得不,边模块化边微服务,模块化的时候要注意,不能有关联查询,包要完全独立,到时候微服务才能拆开。
松耦合表示我们模块之间不直接依赖,无状态,可以单独地为外界提供服务;
强内聚是指,我们虽然要拆分成一个个小的微服务,但是也要考虑某些功能的强关联性,比如一个凳子是由四个脚与一个板组成,我们不能把四个脚与板分开售卖,就没有意义了。
开发
spring-boot :较springmvc更加简约了,springmvc有一大零的配置文件,比如spring-servlet、spring-mybatis、spring.xml与web.xml,这些在spring-boot都不需要了,只需要强大的注解功能即可,boot更合适微服务。
spring-cloud :里面有比较多组件,用于支持微服务,比如spring cloud config统一配置中心,用于多环境的配置文件配置,大家再也不用为多个微服务的开发、测试与生产环境的配置文件管理而发愁了;spring cloud eureka用于服务注册与发现,下面有单独介绍;其它的组件大家可以去官网看看,这里不一一介绍,总之如果JAVA平台,尽量使用spring体系的内容。
我们采用mysql,因为我们是应用多,但数据量单表并不算大,多则不超过百万,mongodb也实验过,开发非常快,也非常灵活,但因为不是关系型数据库,维护成本较高。
RESTFUL :URL的资源与操作解耦,让URL更加符合语义,上百个接口也非常好管理,网上有很多文章讲得非常透彻,这玩意不是特别好理解,要多领悟,在项目中实践,就有矛塞盾开的感觉,这里不做详细介绍。
接口文档swagger :比起传统全手工写接口文档,swagger有统一的输出格式,不管是几个人写的;swagger采用写代码的方式来写接口文档,以前修改了代码,还必须打开wiki手工修改接口文档,现在只需要修改一下代码即可,程序员更愿意修改了,成本更低了,前端与其它调用者不会天天吼着,你这接口咋又变了,新加的字段是啥意思呀。
RocketMQ:一直纠结kafka与rocketMQ,最终选择了RocketMQ
为了性能上面的考虑,尽量使用异步编程,比如注册送优惠券,那么注册成功就可以给用户返回注册成功了,但是送优惠券可以是异步调用的,不阻塞注册的线程。
微服务框架下,日志不可能还分散在各个服务节点上,必须有统一的日志中心。ELK是一个实时日志分析平台,就是将各个服务的日志汇总于日志中心,然后可以按照系统、节点等进行搜索,除上述搜索条件外,我们还在各个微服务实现了按照业务id(一次请求生成一个业务id)与用户id搜索日志,方便跟踪与定位问题。
当然可能有更加轻量级与好用的disconf或spring cloud config,但是我们有php开发的应用,以上二者都不支持。如果全是JAVA应用,采用disconf还是非常不错的。
测试
每个程序员都有这样的经历,刚上线,客户又反馈了bug,原来是我们修改某个功能代码的时候,导致了其它功能的bug,每次上线心里都没底;这就体现了接口测试的必须性,尤其是每次版本升级的时候,都需要执行一遍,以防修改某个接口导致其它接口报错,比手动测试靠谱许多。
部署
docker已经家喻户晓了,这是继虚拟机以后,又一重大变革,将所有的单个微服务都放在docker中,这样你何时何地想部署,直接丢过去就OK了,快到爆。
用几句简单的命令就搞定了负载均衡,而且还可以平滑升级,版本升级的时候,大家就不用告诉客户:系统通知,某日某晚00:00-08:00我行处于系统升级维护中,大家不要去取钱哦,因为你可能取不出来,呵呵。
升级
我们采用工具flyway,可以对数据库脚本进行版本控制。
传统的版本升级,
1.开发推代码并同时记录自己提交了哪些文件;
2.项目经理根据svn审核文件,并打包成war包;
3.投到测试环境让测试公司测试;
4.中途修改了文件,可能需要重新打包;
….
我都写不下去了,项目经理像个超人似的。
现在用持续集成(CI)非常简单,我们用的工具是Jenkins,推完代码,点几下按钮就完成了上线,不管是测试环境,还是生产环境都非常简单,不然项目经理核对文件眼睛都绿了。
结尾
本文主要是介绍微服务开发上的选型,对于细则不做深究,大家感兴趣可以了解下各个组件。当然,我们的选型未免正确,不同场景应用可能完全不同,本文仅供参考。
百万在线直播互动平台基于Docker的微服务架构实践
本文从具体的项目实例出发和大家讨论如何从无到有地去搭建一个能够快速伸缩的微服务架构。
2017 年 12 月 1 日-2 日,由 51CTO 主办的 WOTD 全球软件开发技术峰会在深圳中州万豪酒店隆重举行。
本次峰会以软件开发为主题,新浪微博研发中心平台高级系统研发工程师温情在微服务与容器技术专场带来了主题为“基于 Docker 的微博直播互动微服务架构”的精彩演讲。
本文将围绕以下主题,探讨直播互动的微服务架构设计:
针对现在非常火热的直播场景,如何设计一个稳定的消息互动系统,以支持百万级消息的互动分发。
在服务越来越复杂的情况下,如何对系统进行合理地组件化拆分,进而实现以微服务的方式进行独立部署和升级。
在混合云的体系下,如何充分利用 Docker 技术和公有云的弹性特性,设计一个基于混合云的弹性化的架构,以实现在流量突增且无人看守的情况下,自动完成服务的弹性伸缩。
微博直播互动平台的背景与挑战
2017 年可谓直播大年,新浪微博在自己的 App 推出了直播服务,同时也打通了与淘宝、一直播、红豆等平台的互动。
从技术上说,直播一般分为两个部分:
视频流,包括流媒体的传输部分。
直播互动,包括评论、点赞、送礼等其他部分。
直播的特点是:由于房间里人数众多,直播平台需要能够支持百万用户同时在线的场景。
微博直播平台特点
直播互动系统的基本模型是一个消息转发的系统,即某个用户发送一条消息,其他用户收到该消息,并执行相应的存储。
消息系统一般具备三个基本的评判标准:实时性、可靠性、和一致性。对于直播这种消息系统而言,它对于可靠性和一致性的要求并不高,而对实时性的要求却非常高。
如果用户给主播送完礼物 10 秒钟或者 1 分钟之后,主播才能收到并回复。这是不可接受的。因此我们需要具有“秒级”的实时性。
微博直播互动的特点:
平时的流量不太大,但是当访问多的时候流量会产生明显的猛增。
流量的激增表现在消息推送量的巨大。一般可以达到每秒千万条消息推送。
对于一般短连接的请求而言,用户为了进入界面仅发送一次请求,后续通常不再产生其他操作,因此服务器端的压力不太大。
而直播互动场景则不同,在用户加入房间之后,就算不做任何操作,也会收到一大堆的推送。这种实时性高的推送方式会给服务器造成持续的压力。
微博直播平台面临的挑战
由于用户对直播的需求量大,且玩法多样,我们面临了来自三个方面的挑战:
如何快速迭代并快速地响应需求,这是对业务以及系统的衡量标准。
如何应对全量 Push 所引发的流量峰值。
如何实现成本最优化,即如何运用有限的资源应对波峰波谷的交替。
微博直播互动平台微服务架构演进
针对上述三大挑战,我们自己搭建了直播互动的微服务架构。上图是直播互动的架构图,我们对业务层进行了模块化的划分,包括发现服务、三方平台服务、推送服务等各种微服务。
架构选型
在架构选型方面,我们先来看传统的单体模式。单体适用于许多场景,特别适合于敏捷开发。
由于微博互动的流量庞大,且系统相对复杂,因此会面临如下问题:
上线成本高,迭代速度慢。单体模式是将所有的服务集中在一块儿,实现一起部署和一起上/下线。因此任何一次细微的改动,都需要我们重新“上线”。
而为了扫清可能出现的服务问题,我们一般会进行全量回归测试。可见这种缓慢的迭代速度是我们所无法接受的。
可伸缩性差。在服务进行水平扩展时,随着服务增多,Redis 和 DB 的连接数也会逐步增多,而每个资源都有一定的连接数瓶颈,当服务增长到一定数量之后,则会导致服务无法进一步地水平扩展。
鲁棒性差。系统中任何一处的 Bug,都会导致其他的服务,甚至是整个服务的瘫痪。
而微服务与单体之间的区别在于:微服务会将一些共同功能予以拆分,并且在拆分的基础上,每个模块都能维护自己的 DB 与资源。
因此微服务的好处体现在:
每个服务都被独立地开发和部署,迭代速度明显提高。我们不必测试全部,只需测试自己所开发的服务便可。
单个服务所依赖的资源变少,且扩容的速度明显提高。特别是对于一些轻量级的服务,我们能够保证在 30~40 秒内,完成扩容并启动。
通过 RDC 或者相关的调用,移除一些推送服务对于 DB 和 Redis 的直接依赖,从而解决连接数的问题。
将各个服务独立进行部署,从而避免了那些无关联的服务问题所引起的整体宕机,将 Bug 限定在单个模块中。
微服务化难题
微服务的引入也带来一些新的问题:
以前在单体模式中,我们将各个模块杂糅在一起,不必详细考虑。如今采用微服务了,应当如何进行合理的拆分呢?
以前只是本地调用,现在改成了微服务,它们将如何通信?如何考虑网络开销呢?
在服务部署之后,微服务如何去发现问题呢?
难题一:服务拆分
对于微服务的拆分,大家最为关心的问题是拆分的力度。我们采取了如下简单的方式,大家可以在自己的项目中稍做借鉴:
不知如何拆分时,可“一刀两断”地直接拆分成核心和非核心服务。其好处是对服务做到相应的隔离。
例如:在服务器不够用时,我们只保护核心的服务,而非核心服务不会影响到核心服务。因此是一种根据业务重要性的拆分方式。
服务治理,可以随时对非核心服务予以降级。我们让有限的机器资源去支撑核心的服务。
完成了基础拆分之后,我们就可以根据业务场景对核心服务进行进一步的拆分:
针对 Short Service,我们有一个叫做 Wesync 的私有协议解析。由于我们平时并不会修改其代码,而且该协议的解析具有通用性,因此我们将其拆分出来单独进行部署。
我们将所有与业务相关的服务,如房间和消息等,全部放置在一个叫 Biz Service 的服务中进行部署。这一部分的代码量会非常大,但是代码量并非服务是否拆分的衡量标准,由于其处理复杂业务的压力并不大,因此可以将它们归纳到一起。
将 Push Service 这一推送服务进行拆分,它可以维护与用户之间的长连关系,从而保证消息推送的实时性。另外服务端“推”的方式会比用户端“拉”的方式更具有实时性。
我们对于 Push Service 进行拆分的原因在于:
由于消息的推送量巨大,Push Service 成为了整个服务的瓶颈点。假想在一个 10 万人的房间中,如果 1 秒内有 10 个人群发了消息到客户端上,那么系统会产生 100 万条每秒的推送量。
同理,如果房间里有 100 万人,则会产生 1000 万的推送量。可见该消息量的量级是非常大的,因此 Push Service 是我们需要频繁扩容的服务。
我们在设计时会希望 Push Service 尽量简单,并让它对资源减少依赖。
我们简单地从业务角度对非核心服务进行了如下拆分:
Barrage Service:包括直播回访功能和获取历史消息。
Third Service:与三方平台的接入服务。
我们来看 Barrage Service 的拆分原因:由于该服务是一种用来批量获取历史消息的对外暴露式服务,那么批量地获取历史消息必然会带来大量的带宽消耗。
因此,我们需要采取如下的优化方式:
我们采用 Gzip 的压缩技术对接口和返回的数据进行压缩,从而减缓对于带宽的消耗。
充分利用 CPU 和其他硬件的性能。
增加多层缓存的策略,我们可以直接在本地 load,而不必去 DB 或 message cache 里 load,因此减少了与外界的交互。
如上图所示,我们在进行微服务化拆分之前,各个服务被杂乱无章地杂糅在一起,我们不得不一起部署。因此,我们根据各种策略,按照上述方法进行了服务的拆分。
难题二:服务通信
同时我们也从同步与异步的角度,对服务之间的通信进行了拆分:
同步操作:REST 的 API 方式+RPC 方式。
异步操作:主要围绕的是消息队列。
对于核心服务和非核心之间的通信交互,我们进行了场景分析。如上图所示,第三方服务(Third Service)包含两个方面:
蓝线部分表示第三方服务器推送(Push)消息到我们的系统。由于我们希望第三方来的消息能够更为实时地(同步)展现到我们 App 的前端,因此采用的是 RPC 类型的 Push 方式。
红线部分表示我们从微博 App 产生消息,然后对外传递给第三方服务器,让他们以 Pull 的方式来获取消息。由于我们不希望其他的服务、后面的服务、以及非核心服务影响到我们的核心服务功能,因此我们实现的是异步解耦,即采用 Queue 类型的 Pull 方式。
对于 Barrage Service,我们采取的是共享数据库的方式。由于批量获取回放消息是一项大量消息带宽的服务,因此我们共用一个数据库,通过直接从库里 load,以保证系统资源的提供。
难题三:服务发现
对于 Push Service 类型的服务发现,我们弃用了以前挂在 DNS 处让 DNS 做服务发现的方式,而是采用了自己写的 Dispatch Service。
它的运作机制是:
为了在用户加入房间之前建立一个长连的过程,我们发送一个 Dispatch 与 Push Service 建立相应的连接。一旦有消息产生,则通过 Push Service 进行推送。
Dispatch Service 可以动态地去根据用户所属的服务器和区域,按照策略就近做出相应的选择。
该策略可以支持 Push Service 的水平扩容。即在扩容之后,我们不再给老的 Push Service 推送流量,也不再返回相应的 IP,而是把全部流量导入新的 Push Service。
而对于 RPC 类型的服务发现,我们采用典型的 SOA 架构,包括:Registry 提供可用服务列表、Server 提供服务、Client 发现并使用服务。因此,我们采用的是 Motan RPC,以快速地响应各种需求并完成发现。
微服务化总结
总结起来,微服务解决了如下四方面的问题:
独立开发测试,加快了迭代的速度。
通过服务拆分,减少了无关联服务之间的影响。
通过减少对资源的依赖,提高了服务扩展的速度。
当然也增加了服务的部署和运维的难度。
既然采用了快速扩容的框架,那么我们就需要运维同学的参与和部署。下面来讨论直播互动的弹性扩缩容策略。
微博直播互动平台的弹性扩缩容
基于 Docker 的混合云架构
由于对微博的使用是一个典型的流量激增场景,因此如果采用盲目购置服务器这一传统的应对方案的话,会造成整体负载饱和度的不均衡。
例如,大家一般在白天和半夜都不会去“刷微博”,服务器和网络的利用率会比较低。只有在晚高峰出现时才会有爆炸式负载的产生。
因此我们采用了快速弹性扩缩容的应对策略,即利用公有云端的各种快速弹性伸缩的资源服务。
但是,由于之前的私有云环境是在我们自己完全掌控的范围内,而如今引入的公有云则带来了环境上的差异性问题。于是我们参考业界的普遍方案,采用了 Docker。
Docker 的网络模型选择一般有 Bridge、Container 和 Host 等实现方式:
我们起初在测试环境中采用了 Docker 的默认设置 Bridge 模式。
Docker 在通过 Daemon 启动时会有一个 Docker0 的虚拟以太网桥。
Docker 的 Daemon 运用 veth pair 技术进行虚拟化,即在容器内与宿主机之间建立虚拟网卡连接,而在容器外进行相应的消息转发。
因此我们采用了 Host 模式,即:
在 Host 模式下的同一个 eth0 可以被共用,因此各方能够共享宿主机的网络命名空间。
同时由于它省去了各种路由的开销,因此会比 Bridge 模式更快。
可见,Docker 的优点在于简单轻便,非常适用于微博的应用场景。另外,再加上公有云端的一些资源,共同构成了基于 Docker 的混合云架构,我们称为 DockerDCP。
值得一提的是 DCP 已经开源了,在 GitHub 上有一张 Open DCP 的服务图,大家可以去搜索一下。
DCP 的作用是能够在 10 分钟之内扩容并部署 1000 台机器,以应对诸如“三大节日”的流量猛增。
因此,它每天都会有着 6000 亿次 API 的调用,以及万亿次的 RPC 调用。
为了让直播互动与 DCP 实现相关的自动化运维部署与扩缩容,我们每次都会将消息推送至 SLB(负载均衡),通过 Push Service 的推送服务来实现跨网服务的部署。
要想实现扩容首先要获知设备的来源。DCP 能够帮助我们区分内网和外网(公有云)不同的机器。
例如:内网的三个业务方— A、B、C 都有自己的多台服务器,而我们将它们设置为一个“共享池”。
业务 C 会因为峰值流量而申请池中的 3 台服务器,而在业务空闲时则将资源归还到池中。如此,我们可以自由地在私有云和共有云上实现快速扩容,即为“双云扩”。
自动化扩缩容流程
我们直播互动的自动化扩缩容流程大致分为:
制定监控的指标,即设定达到何种监控指标的阈值,才开始扩容操作。一般是通过压力测试来获取到。
监控指标的采集,包括如何进行采集,以及采集哪些指标。
数据流转到容量决策系统,以决定是否进行扩容。
一系列服务扩容的标准流程,如上图所示。
而缩容的流程与上述扩容流程较为类似,在此就不赘述了。
对于上述提到的监控指标,我们分为两大类:
业务性能指标,不同的业务之间会存在着差异,有的 API 服务能够支撑 1000 个 QPS(Query Per Second),而有的却只能支撑 200 个。因此根据业务的不同,我们所采集和监控的性能指标也不尽相同。
机器性能指标,侧重的是通用化的机器性能指标,包括带宽、PPS、CPU、性能、IOPS 等。只要发现哪一块出现了瓶颈,就应当去尽快扩容。
相对应地,指定监控指标的流程为:对性能系统进行相应的压力测试>发现服务的瓶颈点>对瓶颈点进行分析>制定监控的指标。
如今我们也正在尝试着通过机器学习来实现自动化监控。我们一般会每周或是定时对各种服务进行压力测试,以及时地去发现服务的瓶颈。
由于新引入的机器可能会导致整体性能的不一致,而且随着服务需求和代码量的增多,整体服务的瓶颈点也可能会相应地迁移到其他地方,因此我们通过进化版的压力测试,实现了对瓶颈点的实时把握。
就 Push Service 的指标监控而言,我们在压力测试时所监控的业务性能包括:
用户数据的长连数。因为单台机器可能会撑起几千个用户长连数。
消息推送量。在某些的业务场景中,可能长连数并不多,但是其消息推送量却非常大。因此我们需要从不同的维度实施监控。
而对于机器性能的指标,同样会包括带宽、PPS、CPU、内存、IOPS 等。
就监控指标的采集而言,我们分为两个方面:
业务的性能指标是由各个业务系统负责相应的采集。
机器的性能指标是由运维监控服务执行统一的采集。
弹性扩缩容总结
总结起来,我们在弹性扩缩容方面实现了如下三点:
通过容器技术 Docker 化的服务解决了环境差异性问题。既实现了更快速扩缩容,又让整个虚拟化更为标准。
通过混合云架构 DCP 解决了资源弹性伸缩的问题。
在架构搭建之后,通过自动化扩缩容实现了直播无人看守的场景。
典型案例分享
下面是在实现扩缩容架构之前与之后的两个直播案例的对比。
未实现自动化扩缩容时,我们曾做过对神州飞船回收的直播。由于发生在凌晨 3 点多、且各方人员并未被通知到,因此我们在不清楚会有多少观看流量的情况下采用了全量 Push。
通过次日的事后分析,我们发现:服务的流量已触及瓶颈点,出现了许多的报警,幸好有人员值班,所以并未出现故障。
从维护团队过于疲惫和服务保障的角度出发,我们决定开始着手实施自动化扩缩容。
如上图所示,这是我们在实现了自动化扩缩容后的一次直播。左侧图中蓝线的每一次波谷代表一次扩容操作。
在波谷处于最小长连数时,由于自动扩容出了一堆机器,因此那一时刻并无流量的进入,连接数基本为零。
之后连接数随即迅速上升,服务在 30 分钟之内做了 4 次快速自动扩容。而这些自动化扩容对于运维人员来说都是透明的,只是在扩缩容时会有邮件提醒而已。
编辑:陈峻、陶家龙、孙淑娟
投稿:有投稿、寻求报道意向技术人请联络 editor@51cto.com
温情,新浪微博高级系统研发工程师,从事微博视频和通讯相关系统的研发。当前负责微博直播消息互动系统的研发,推崇高可用,可弹性伸缩,低耦合的微服务架构设计。技术上擅长消息通讯方向,针对系统应对突增流量和高并发方面有丰富的实践经验。
精彩文章推荐:
以上是关于微服务架构实践 - 你只懂docker与spring boot就够了吗?的主要内容,如果未能解决你的问题,请参考以下文章
微服务架构实践 - 你只懂docker与spring boot就够了吗?