链家网房源平台微服务架构实践
Posted InfoQ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链家网房源平台微服务架构实践相关的知识,希望对你有一定的参考价值。
编辑|小智
链家网从线下化到线上化,从线上化到规模化,背后有一套庞大而复杂的服务系统支持。随着公司的转型升级,业务变化更加的快速而多样化,系统的访问量也随之增加。如何快速的推进业务的发展,保障系统的稳定性?链家网通过实践微服务架构,降低系统复杂度,提高交付效率,并结合自研监控系统保障系统高可用。
与其说是诉求,不如说是我们要解决的问题。永恒的诉求,就是解决所有已有的问题。
影响业务的变化的要素有很多,不同的城市,不同的交易类型,不同的房屋属性,价格的变化等等,都可能影响我们的运营策略。同事,公司自身的业务模式也在不停的转变,例如我们支持直营,加盟,第二品牌等多种模式。
稳定性的要求,每天早上 8 点 15 万经纪人同时登录的流量挑战以及每天来自内网,外网的数十亿次访问量 Hits。而这是只开通了 28 个城市的情况,目标是面向全国,服务全国 150 万的经纪人,如何以后会同时上线多个城市的流量激增。
而我们并不是构建一套微服务,而是转型微服务架构,如果使用微服务的架构,对原有业务的影响,重构系统的代价也是一个要考虑的问题.
那么下面就带着我们的痛点,开启我们今天的实践之路。
实践之路我们大致概括为四个部分,首先,是选择一个合适的开发利器,符合微服务的需求,使用起来简单,扩展性好,最好学习成本也不高。然后,我重新审视我们现有的架构,分析一下在技术上需要做的取舍,它相对微服务还差什么,需要补充的是什么。接下来,介绍一下我们下功夫最大的,也是最有特色的部分,利用这个平台如何完成可用性的保障的。最后,回到微服务最贴近业务的一个核心“拆”,我们微服务拆分的过程是有分有合的。
对比之下,spring boot 有明显优势,它不仅功能强大,易于扩展,而且对于我们现有的架构十分契合,几乎没有迁移成本。相比之下,Jersey 偏向于接口开发,功能性稍差,而 DropWizard 功能齐全,但是内置容器单一,而且有一定的迁移成本。
选定 spring boot 我们就按照 spring boot 的玩法。如果用过 spring cloud 的话就应该知道,基于 spring boot 引入 spring cloud 的话是十分容易的,只需要引入依赖,代码中一行注释就能实现功能的引入。那我们也想在开发中享受这种便利,于是,我们基于 spring boot 扩展了我们大部分中间件产品的接入 starter,从而简化开发过程。
除此之外,我们还利用 spring boot 的 endpoint 扩展了服务的监控能力(监控检查,服务下线等)。这个功能在后面有很多应用。
在开发启动器的时候会让你重新深入地了解一遍这些技术,如何自动接入,怎么简化配置,如何定义 metrics,设计 endpoint 执行 actuator 等等。
除此之外,我们还在 boot 的基础上,开了适应于特殊业务场景的开发框架。
以录入一套房子为例,同样的录入流程,租赁还需要关注家具状况。以往的开发过程,需要对录入房子的逻辑做一部分特殊处理,如果是租赁类型,则处理家具相关逻辑。这是一种普遍场景,内部很多业务都有这种需求,针对这个情况,我们开发了我们的个性化框架。该框架的目的是简化开发过程,让开发只关注业务场景,而何种情况下执行何种业务场景,都交给配置中心。
业务请求被控制层拦截,控制器会去配置中心加载对应的类型的数据,然后根据类型定位个性化服务的处理类,执行个性化业务。而个性化业务是否执行依赖于配置的数据,数据变化则业务执行也会切换。例如配置中配置了买卖和租赁两种类型,则买卖和租赁业务都会执行处理家具的逻辑。
当特殊业务依赖城市配置时,可以实现灰度上线;当特殊业务依赖异常配置时,可以实现服务降级。
通过对 spring cloud 的调研,全面衡量成本和上下游影响;以及对现有的技术体系功能性评估,我们决定还是在现有的 dubbo+zk 的基础上构建我们的微服务体系。
选择了现有的技术,就要面对技术中可能有的缺陷,首先是异构系统的服务发现。我们的实现方案是在网关层做了 dubbo 的代理,通过代理将 dubbo 转换成 http 服务。
为什么做在了网关层而没有让 dubbo 直接有提供 http 的能力,这里要考虑一个负载均衡的问题,我们知道 dubbo 的负载均衡做在了 consumer 端,如果直接让 dubbo 提供服务,那消费者要自己实现负载均衡,这肯定是不现实的。负载由我们做,而做在网关层也符合网关的定义,同时,也给了我们一个机会,实现对外的负载均衡和对内的负载均衡的差异化配置。
通过 dubbo 的 echo service 做服务的监控检查。同时提供了服务线下的功能。通过自研框架实现服务的降级。
以前每次上线,都会接到下游系统的大量报警,Dubbo 本身是有优雅停机的功能的,为什么还是有异常报出呢,原因是运维平台不能判断服务的状态,当它使用 stop 脚本没有终止进程的时候,只能强制杀死进程,保证项目能重启成功,导致 hook 根本没有机会执行。我们的方案是重启操作分两步,先下线服务,在重启机器,保证整个服务安全线下并没有流量进入。
大多数监控平台只重视“监”不重视“控”。我们研发了一套业务接口级的监控系统。很多时候业务的指标也能反映出系统潜在的问题。并提供了灵活可配置的监控规则和报警规则。除此之外利用服务自治的能力时间监控平台对服务控制的能力。当服务出现异常报警(cpu 过高或响应时间过长),监控平台会根据异常情况选择下线服务,并对下线的服务开始监控检查,一旦监控检查状态恢复,则重新上线服务。从而实现服务的自动恢复功能。
在拆分方面,我们遵循以下几个原则:
首先,微不是小,并不是简单的把项目拆小部署就解决问题的。按代码量,按业务数都不能用来划分一个微服务的边界。还是要从项目职责,维护成本,交付周期等多个方面均衡考虑在做拆分整合。
再一个就是要业务完整,一方面不希望同一个业务模型的处理在几个项目中来回转,另一方面,不需要有一个独立部署的服务,没有任何独立的功能。
必要的时候需要做重新的整合,这个过程可能不是拆,而主要是合并。毕竟太多离散的服务既不利于维护,又浪费资源。
拆分之后必然要面临很多问题,首先就是跨库查询问题。单纯的多次接口查询不能解决分页和聚合的问题。我们采用的是迂回的战术,将数据重新聚合,利用搜索完成跨库查询的操作。
不保证分布式事务会有出现数据不一致的情况,单纯的通过后期对账来实现数据一致性,不仅实时性差,而且处理起来也十分复杂。业界也有基于 XA 的两阶段提交的方案,进一步保证分布式事务。但是这种方案效率不是很理想,而且比较好的实现一般都是在商业数据库中。我们采用可靠消息 + 回溯 + 数据对账的模式。通过发送可靠消息,消息发送成功即认为事务成功。消息中间件保证消息到达。如果消费端消费失败则重试。后期还可以通过消息回溯的机制保证重试依然失败的消息。
对于技术选型方面,我们需要根据自己实际情况,因地制宜。能在现有的架构上平滑过渡;
我们不希望重复造轮子,但是如果觉得所有的轮子都不适合我们,那不妨就造一个适合自己的;
拆分并不是最终目的,综合考虑项目边界,维护成本,交付周期等再做决定;
面对拆分后资源离散的问题,有时让他们重新聚合也是一种很好的选择。
最后,我们目前的微服务体系还有很多不足之处,后续还有很大的改进空间。智能化运维,更好的安全体系也都是很重要的方向。
技术的路程没有尽头,我们还在路上。
作者介绍
于洋,链家网高级工程师。负责链家网房源系统的开发设计工作,主导推动微服务架构设计落地。多年传统软件和互联网系统开发设计经验。先后就职于用友,Oracle,阿里。
今日荐文
那个逃离北京的程序员说:我想工作到 70 岁
技术浪潮不断来袭,在技术层出不穷的今天,如何洞悉技术前景显得尤为重要,左耳朵耗子等业内资深专家在极客时间开设针对前沿技术、职业发展、商业思维的付费专栏,现正感恩回馈,199 元专栏现 1 元即可阅读,请识别文末二维码。
以上是关于链家网房源平台微服务架构实践的主要内容,如果未能解决你的问题,请参考以下文章