一、接触的服务化中间件
MQ
消息系统,使用多种方式来确保消息可靠的生产、投递和消费,使得生产者和消费者有效解耦,降低了系统复杂性。
为什么要用消息系统?消息系统没有提高系统性能(将消费者和生产者写在一起岂不是更快?),也不是数据源(Redis更佳),而是实现了生产者和消费者的解耦。生产者和消费者各司其职,生产者把消息生产好,至于消息如何交付给消费者,这种交付方式是不是会丢失消息之类的可靠性问题一概不管(这也就是为什么消息队列不仅是一个中间结果存放区的原因)。这个作为中间仓库,负责与消费者打交道,同时保证后续交付可靠性的角色,就是消息队列来担当的。 3
那么如何设计一个完全可靠的消息系统呢?
(1)生产者将生产的消息保存在数据库做持久化;
(2)消息broker接收到消息后也做持久化存储;
(3)消费者请求消息后返回ack,如果请求失败则retry.
RPC系统
对业务透明,提取公共服务。
Dubbo是一个典型的RPC分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架。
如何实现RPC的服务化呢?
(1)服务提供者在服务注册中心注册服务,提供对外接口;
(2)服务使用方从服务注册中心订阅感兴趣的服务;
(3)当服务有变动时,服务注册中心可通知使用方;
(4)服务使用方使用从注册中心得到的接口信息使用服务。
Schedule
分布式任务调度
解决定时任务的单点,定时问题的集中监控,集中管理等问题。
原有的定时任务一般都是单点部署,可靠性不高,并且定时任务就像一个黑洞,要监控定时任务的状态总是一遍遍的添加监控,维护监控。这些工作总是重复进行。
使用Schedule后,处理任务的worker可以多台部署,在任务调度执行时只有一台会参与执行,其中一台离线后Schedule会选择其他worker执行。并且可以通过Schedule提供的管理界面监控任务执行进度,任务执行过程中生成的日志,可以指定任务执行失败后的恢复策略,可以人工介入任务的执行。
Config
配置中心
1、将配置和代码相分离,集中管理所有的配置。配置中心会根据不同的环境下发不同的配置,配合最新的发布系统(QDR),我们可以实现打包一次部署到任意环境,不仅可以节约发布时间,更可以让流程更顺畅(经过测试的war包部署到线上)。
2、监控配置文件的发布流程。 将配置文件的修改和发布透明化;吸取我们之前在使用配置文件时的教训,将使用配置文件的最佳实践融合到发布流程中。
3、热发布配置文件。 在配置中心后台修改配置文件发布后应用会拿到最新的变更。
4、生产环境灰度测试. 修改配置后可以手动将改动推送到生产环境某台机器进行线上测试. 待完全通过后再批量生效。
5、失败回滚机制. 当配置文件解析失败后会自动回滚到上个版本. 保证生产环境稳定运行.
Tracer
分布式链路追踪系统用于在庞大的分布式集群系统的调用关系复杂的情况下,快速定位问题;
分布式链路跟踪系统被广为熟知源于Google Dapper论文,随后Twitter开发了ZipKin,eBay开发了Centralized Activity Logging(CAL),淘宝开发了鹰眼(EagleEye)
ClientDB
分库分表
二、互联网高可用架构,为什么要服务化?
在服务化之前,互联网的高可用架构大致是这样一个架构:
( 1 )用户端是浏览器 / APP 客户端
( 2 )后端入口是高可用的 nginx 集群,用于做反向代理
( 3 )中间核心是高可用的 web-server 集群, 研发工程师主要编码工作就是在这一层
( 4 )后端存储是高可用的 db 集群,数据存储在这一层
更典型的, web-server 层是通过 DAO/ORM 等技术来访问数据库的:
架构痛点一:代码到处拷贝
举一个最常见的业务的例子 -> 用户数据的访问,绝大部分公司都有一个数据库存储用户数据,各个业务都有访问用户数据的需求:
在有用户服务之前, 各个业务线都是自己通过 DAO 写 SQL 访问 user 库来存取用户数据,这无形中就导致了代码的拷贝 。
架构痛点二:复杂性扩散
随着并发量的越来越高,用户数据的访问数据库成了瓶颈,需要加入缓存来降低数据库的读压力,于是架构中引入了缓存,由于没有统一的服务层, 各个业务线都需要关注缓存的引入导致的复杂性。
对于用户数据的写请求,所有业务线都要升级代码: ( 1 )先淘汰 cache ( 2 )再写数据
对于用户数据的读请求,所有业务线也都要升级代码: ( 1 )先读 cache ,命中则返回 ( 2 )没命中则读数据库 ( 3 )再把数据放入 cache
这个复杂性是典型的“业务无关”的复杂性,业务方需要被迫升级。
架构痛点三:库的复用与耦合
服务化并不是唯一的解决上述两痛点的方法,抽象出统一的 “ 库 ” 是最先容易想到的解决:
( 1 )代码拷贝
( 2 )复杂性扩散
的方法。抽象出一个 user.so ,负责整个用户数据的存取,从而避免代码的拷贝。至于复杂性,也只有 user.so 这一个地方需要关注了。解决了旧的问题,会引入新的问题, 库的版本维护与业务线之间代码的耦合 :业务线 A 将 user.so 由版本 1 升级至版本 2 ,如果不兼容业务线 B 的代码,会导致 B 业务出现问题;业务线 A 如果通知了业务线 B 升级,则是的业务线 B 会无故做一些“自身业务无关”的升级,非常郁闷。当然,如果各个业务线都是拷贝了一份代码则不存在这个问题。
架构痛点四: SQL质量得不到保障,业务相互影响
业务线通过 DAO 访问数据库:
本质上 SQL 语句还是各个业务线拼装的,资深的工程师写出高质量的 SQL 没啥问题,经验没有这么丰富的工程师可能会写出一些低效的 SQL , 假如业务线 A 写了一个全表扫描的 SQL ,导致数据库的 CPU100% ,影响的不只是一个业务线,而是所有的业务线都会受影响 。
三、服务化解决了什么问题
为了解决上面的诸多问题,互联网高可用分层架构演进的过程中,引入了“服务层”。
1、调用方友好
有服务层之前:业务方访问用户数据,需要通过 DAO 拼装 SQL 访问;有服务层之后: 业务方通过 RPC 访问用户数据,就像调用一个本地函数一样,非常友好方便。
2、 提高复用性,防止代码拷贝
3、 专注,屏蔽底层复杂度
4、SQL 质量得到保障
5、提供有限接口,无限性能\
在服务化之前,各业务线上游想怎么操纵数据库都行,遇到了性能瓶颈,各业务线容易扯皮,相互推诿;服务化之后, 服务只提供有限的通用接口,理论上服务集群能够提供无限性能,性能出现瓶颈,服务层一处集中优化 。