dubbo系列一、dubbo背景介绍、微服务拆分

一、背景

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

二、传统应用到分布式应用的演进过程

1、单体应用架构

当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键,例如SSM,Spring MVC,配合nginx做负载均衡使用已经满足业务需要。

2、多个垂直应用架构

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。但是不同应用之间无法高效的调用。

3、分布式服务架构

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键,实现不同的应用之间的高效调用。

4、流动计算架构(soa服务化)

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,动态更新调度策略,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

三、微服务的需求

在大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。 

(1) 服务注册与发现: 当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。 

此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。 

并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。 

(2) 服务依赖关系:当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。 

这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。 

(3) 服务监控与统计: 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器? 

为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。 

其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。 

(4) 服务黑名单:规模继续扩大,应用之间不再是扁平的对应关系,开始分层,比如核心数据层,业务集成层等,就算没有出现循环依赖,也不允许从低层向高层依赖,以免后续被逼循环依赖。 

这时,需要在注册中心定义架构体系,列明有哪些层的定义,每个服务暴露或引用时,都必须声明自己应用属于哪一层,这样注册中心能更快的发现架构的腐化现象。 

(5) 服务文档:服务多了,沟通成本也开始上升,调某个服务失败该找谁?服务的参数都有什么约定? 

这时就需要登记每个服务都是谁负责的,并建立一个服务的文档库,方便检索。 

(6) 服务安全:慢慢一些敏感数据也都服务化了,安全问题开始变得重要,谁能调该服务?如何授权? 

这样的服务可能需要一个密码,访问时需带着此密码,但如果用密码,要改密码时,就会很不方便,所有的消费方都要改,所以动态生成令牌(Token)可能会更好,提供方将令牌告之注册中心,由注册中心决定是否告之消费方,这样就能在注册中心页面上做复杂的授权模型。 

(7) 服务限流:就算是不敏感的服务,也不是能任意调用,比如某服务突然多了一个消费者,这个消费者的请求量直接把服务给拖跨了,其它消费者跟着一起故障。 

首先服务提供方需要流控,当流程超标时,能拒绝部分请求,进行自我保护。 

其次,消费者上线前和提供者约定《服务质量等级协定(SLA)》,SLA包括消费者承诺每天调用量,请求数据量,提供方承诺响应时间,出错率等,将SLA记录在监控中心,定时与监控数据对比,超标则报警。 

(8) 服务路由:虽然有SLA约定,如果不能控制,就只是君子协定,如何确保服务质量? 

比如:一个应用很重要,一个不那么重要,它们调用同一个服务,这个服务就应该向重要应用倾斜,而不是一视同仁,当支撑不住时,应限制不重要应用的访问,保障重要应用的可用,如何做到这一点呢。这时,就需要服务路由,控制不同应用访问不同机器,比如: 
应用分离: 
consumer.application = foo => provider.host = 1,2,3 
consumer.application != foo => provider.host = 5,6 
读写分离: 
method.name = find*,get* => provider.host = 1,2,3 
method.name != find*,get* => provider.host = 5,6 

(9) 服务自动化测试  :服务上线后,需要验证服务是否可用,但因防火墙的限制,线下是不能访问线上服务的,不得不先写好一个测试Main,然后放到线上去执行,非常麻烦,并且容易忘记验证。 

所以线上需要有一个自动运行的验证程序,用户只需在界面上填上要验证的服务方法,以及参数值和期望的返回值,当有一个服务提供者上线时,将自动运行该用例,并将运行结果发邮件通知负责人。 

(10) 服务编排 :服务应用和Web应用是有区别的,它是一个后台Daemon程序,不需要Tomcat之类的Web容器。但因公司之前以Web应用为主,规范都是按Web应用的,所以不得不把服务跑在一个根本用不上的Web容器里,而搭一个这样的Web工程也非常费事。 

所以需要实现一个非Web的容器,只需简单的Main加载Spring配置即可,并提供Maven模板工程,只需mvn dubbo:generate 即可创建一个五脏俱全的服务应用。 

(11) 服务开发IDE  :开发服务的人越来越多,更注重开发效率,IDE的集成支持必不可少。 

通过插件,可以在Idea、Eclipse中直接运行服务,提供方可以直接填入测试数据测试服务,消费方可以直接Mock服务不依赖提供方开发。 

(12) 服务审批:因为暴露服务很简单,服务的上线越来越随意,有时候负责服务化的架构师都不知道有人上线了某个服务,使得线上服务鱼龙混杂,甚至出现重复的服务,而服务下线比上线还困难。 

需要一个新服务上线审批流程,必须经过服务化的架构师审批过了,才可以上线。 

而服务下线时,应先标识为过时,然后通知调用方尽快修改调用,直到没有人调此服务,才能下线。 

(13) 服务兼容性检测:因服务接口设计的经验一直在慢慢的积累过程中,很多接口并不能一促而蹴,在修改的过程中,如何保证兼容性,怎么判断是否兼容?另外,更深层次的,业务行为兼容吗? 

可以根据使用的协议类型,分析接口及领域模型的变更是否兼容,比如:对比加减字段,方法签名等。 

而业务上,可能需要基于自动回归测试用例,形成Technology Compatibility Kit (TCK),确保兼容升级。 

(14) 服务降级:随着服务的不停升级,总有些意想不到的事发生,比如cache写错了导致内存溢出,故障不可避免,每次核心服务一挂,影响一大片,人心慌慌,如何控制故障的影响面?服务是否可以功能降级?或者资源劣化? 

应用间声明依赖强度,哪些功能强依赖,哪些弱依赖,然后基于依赖强度,计算出影响面,并定期测试复查,加强关键路径上的服务的优化和容错,清理不该在关键路径上的服务。 

提供容错Mock数据,Mock数据也应可以在注册中心在运行时动态下发,当某服务不可用时,用Mock数据代替,可以减少故障的发生,比如某验权服务,当验权服务全部挂掉后,直接返回false表示没有权限,并打印Error日志报警。 

另外,前端的页面也应采用Portal进行降级,当该Portal获取不到数据时,直接隐藏,或替换为其它模块展示,并提供功能开关,可人工干预是否展示,或限制多少流量可以展示。 

(15) 服务调用链跟踪 :当已有很多小服务,可能就需要组合多个小服务的大服务,为此,不得不增加一个中间层,暴露一个新服务,里面分别调其它小服务,这样的新服务业务逻辑少,却带来很多开发工作量。 

此时,需要一个服务编排引擎,内置简单的流程引擎,只需用XML或DSL声明如何聚合服务,注册中心可以直接下发给消费者执行聚合逻辑,或者部署通用的编排服务器,所有请求有编排服务器转发。 

(16) 服务使用情况报告、服务权重动态调整 :并不是所有服务的访问量都大,很多的服务都只有一丁点访问量,却需要部署两台提供服务的机器,进行HA互备,如何减少浪费的机器。 

此时可能需要让服务容器支持在一台机器上部署多个应用,可以用多JVM隔离,也可以用ClassLoader隔离。 

(17) 服务自动化部署:多个应用如果不是一个团队开发的,部署在一台机器上,很有可以误操作,停掉了别人的服务。 

所以需要实现自动部署,所有的部署都无需人工干扰,最好是一键式部署。 

(18) 服务自动化调度:机器总是的闲时和忙时,或者冗余机器防灾,如何提高机器的利用率? 

即然已经可以自动部署了,那根据监控数据,就可以实现资源调度,根据应用的压力情况,自动添加机器并部署。

如果你的应用是国际化的,有中文站,美国站之类,因为时差,美国站的机器晚上闲的时候,可能正是中文站的白天忙时,可以通过资源调度,分时段自动调配和部署双方应用。 

 

四、传统服务拆分

1、传统服务分为MVC

  • 视图层:负责解析成页面
  • 控制层:负责业务逻辑关系
  • 数据层:orm访问数据库

每个模块一个包,每个包都有自己的MVC,项目迭代久了之后,包就会变得越来越大,业务、代码交错纵横,管理混乱,大部分都共享一个库。

2、常见微服务拆分

  • 把相关性紧密的业务或模块单独拆分成一个服务(代码、数据库单独管理)。
  • 公共模块拆分成一个服务,提供接口给其他模块调用。
  • 使用dubbo分布式服务框架进行服务间的远程调用(消费者-生产者)

常见电商系统拆分:

 

3、微服务拆分优点

  • 解耦,这样每个子系统或者服务器都可以由专门的团队去负责,解决模块之间的耦合以及扩展性问题,即各个子系统都是相对独立的。

  • 容错,每个子系统都是单独部署在服务器上的,如果集中部署在一个服务器上,当这台服务器宕机了就会导致整个系统都不能使用。

  • 集群,同一个服务可以部署部署多台机器。
  • 性能更好,拆分成多个服务之后,相当于均分了单个系统应用的压力,整个为服务系统能承受更大的压力。
  • 微服务架构与语言工具无关,自由选择合适的语言和工具,高效的完成业务目标即可

4、微服务拆分缺点

  • 依赖服务变更很难跟踪,其他团队的服务接口文档过期怎么办?依赖的服务没有准备好,如何验证开发的功能。

  • 部分模块重复构建,跨团队、跨系统、跨语言会有很多的重复建设。

  • 微服务放大了分布式架构的系列问题,如分布式事务怎么处理?依赖服务不稳定怎么办?

  • 运维复杂度陡增,如:部署物数量多、监控进程多导致整体运维复杂度提升。

上面这些问题我们应该都遇到过,并且也会有一些解决方案,比如提供文档管理、服务治理、服务模拟的工具和框架; 实现统一认证、统一配置、统一日志框架、分布式汇总分析; 采用全局事务方案、采用异步模拟同步;搭建持续集成平台、统一监控平台等等。

 5、四个拆分原则

1.AKF拆分原则

AKF扩展立方体(参考《The Art of Scalability》),是一个叫AKF的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。

X 轴 :指的是水平复制,很好理解,就是讲单体系统多运行几个实例,做个集群加负载均衡的模式。

Z 轴 :是基于类似的数据分区,比如一个互联网打车应用突然用户量激增,集群模式撑不住了,那就按照用户请求的地区进行数据分区,北京、上海、四川等多建几个集群。

Y 轴 :就是我们所说的微服务的拆分模式,就是基于不同的业务拆分。

场景说明:比如打车应用,一个集群撑不住时,分了多个集群,后来用户激增还是不够用,经过分析发现是乘客和车主访问量很大,就将打车应用拆成了三个乘客服务、车主服务、支付服务。三个服务的业务特点各不相同,独立维护,各自都可以再次按需扩展。

 

2.前后端分离

前后端分离原则,简单来讲就是前端和后端的代码分离也就是技术上做分离,我们推荐的模式是最好直接采用物理分离的方式部署,进一步促使进行更彻底的分离。不要继续以前的服务端模板技术,比如JSP ,把Java JS HTML CSS 都堆到一个页面里,稍复杂的页面就无法维护。这种分离模式的方式有几个好处:

  • 前后端技术分离,可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果会更好。

  • 分离模式下,前后端交互界面更加清晰,就剩下了接口和模型,后端的接口简洁明了,更容易维护。

  • 前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支撑前端的web UI\ 移动App等访问。

3.无状态服务

 

 

 

对于无状态服务,首先说一下什么是状态:如果一个数据需要被多个服务共享,才能完成一笔交易,那么这个数据被称为状态。进而依赖这个“状态”数据的服务被称为有状态服务,反之称为无状态服务。

那么这个无状态服务原则并不是说在微服务架构里就不允许存在状态,表达的真实意思是要把有状态的业务服务改变为无状态的计算类服务,那么状态数据也就相应的迁移到对应的“有状态数据服务”中。

场景说明:例如我们以前在本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。

4.Restful通信风格

作为一个原则来讲本来应该是个“无状态通信原则”,在这里我们直接推荐一个实践优选的Restful 通信风格 ,因为他有很多好处:

  • 无状态协议HTTP,具备先天优势,扩展能力很强。例如需要安全加密是,有现成的成熟方案HTTPS可用。

  • JSON 报文序列化,轻量简单,人与机器均可读,学习成本低,搜索引擎友好。

  • 语言无关,各大热门语言都提供成熟的Restful API框架,相对其他的一些RPC框架生态更完善。

当然在有些特殊业务场景下,也需要采用其他的RPC框架,如thrift、avro-rpc、grpc。但绝大多数情况下Restful就足够用了。

 

五、dubbo 介绍(角色、调用关系、特性)

1、节点角色说明

节点角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

2、调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

3、dubbo特性

Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。

1、连通性

  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
  • 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
  • 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
  • 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者

2、健壮性

  • 监控中心宕掉不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

3、伸缩性

  • 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
  • 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者

posted on 2018-09-25 22:27  小人物的奋斗  阅读(2980)  评论(0编辑  收藏  举报

导航