内容来源: 2017 年 4 月 22 日, 沪江学习系统技术经理黄凯在 "[沪江技术沙龙] -- 漫谈微服务架构实践" 进行任务也是微服务 -- 沪江任务调度系统微服务化介绍演讲分享. IT 大咖说 (id:itdakashuo) 作为独家视频合作方, 经主办方和讲者审阅授权发布.
嘉宾演讲视频地址: http://suo.im/4NWSu8
摘要
微服务是一种分布式解决方案, 它整合了过去十年来的新概念和技术. 在这个满大街都是微服务的年代, 如何使用好微服务是值得研究的议题. 今天我以沪江的任务调度系统为例, 从架构拆分, 测试, 部署到监控, 引申出我厂微服务化的设计思想.
什么是微服务
微服务是一些协同工作, 小而自治的服务. 它是 SOA 的一种特殊表现形式, 但在通信协议和三方组件的选择上是不同的, 微服务的颗粒度要比 SOA 小.
当服务越来越小的时候, 微服务架构的优点和缺点也就越明显. 优点是服务越小就越不容易出错, 性能也越高. 缺点是当微服务变多的时候, 对于测试人员和运维人员来说工作量要翻倍. 我们认为如果一个服务能够在两个星期内重构, 这样的颗粒度大小就是正好的.
我们以沪江的任务调度系统举例. 上图中是我们的第一代调度系统. Task Center 专门用于分发任务, 并会启很多很多 worker 线程进行工作, 架构非常简单. 这种架构的问题就在于它不适宜扩展, host 如果宕机了, 所有业务就只能停下来等它修复, 这是一个很严重的问题. 针对这个问题我们做了第二代调度系统.
首先我们做了业务拆分. 我们把业务理解成一个工厂的流水线, 有一个 "Boss" 专门负责接任务, 然后把任务发到流水线上. Worker 们从流水线上拿一个合适的任务去做, 第一个 worker 完成后交还给流水线, 下一个 worker 再去流水线上找合适的任务做. 每一个 worker 都对应一个不同的 DB 进行存储它的状态信息, boss 也有 DB 存储自己的状态信息, 这两种 DB 是分开的.
这种架构拆解把一个单例的应用拆成好几个小的项目, 而且每个小的服务可以做高可用, 比如启多个 boss 和 worker. 但同时也会发现其他问题: 当任务特别繁忙, 需要横向扩展一些 worker 进行工作时, 只能新加一台机器, 在这台机器上再启两个 worker. 但空闲时这些新增机器没有办法再回收了.
针对这种资源利用率不高的情况, 我们又做了一个改版.
我们在第三代任务调度系统中引入了些中间件. Mesos 是我们引入的第一个中间件, 它专门用于做资源调度, 主要是帮我们调度 worker. 只要通过 API 告诉 Mesos 通过什么策略来分配 worker,Mesos 就会自动在集群内寻找合适的资源启动任务. 通过这套系统, 我们不仅能完成现有业务任务, 还可以扩展给其他任务型业务使用.
架构拆解过程
对于微服务的拆分, 我总结为以下三点:
结构分离: 要从业务的角度把任务与调度分开, 把任务的生产者和消费者分开, 还要把任务记录与业务逻辑也分离.
数据库分离: 首先要整理出数据库的外键, 从而寻找方法打破外键关系, 其次就是分离共享数据.
事务分离: 目前业界有两种方式, 第一种是做分布式事务, 但这种方法比较慢, 而且设计也很复杂. 另一种方法就是追求最终一致性. 选择哪种方式还需要结合各自的业务场景进行选择.
测试
推行微服务在测试阶段也会遇到一些问题. 比如 TEST CASE 增多, 单个流程走不通, 性能测试也变得非常重要.
上图为比较通用的测试金字塔, 在微服务时代, 金字塔的每一层测试都有不同的测试方法, 这里不一一列举. 这里主要讲一些重要的测试手段.
MOCK 与打桩
MOCK 数据: 微服务常常由于功能过小, 上下依赖严重, 如果要测试单个服务, 必须模拟上游数据, Mock 就成为常规的测试手段. 这里分为外部依赖的 MOCK 数据和内部之间的 MOCK 数据.
打桩服务: 经常制作 Mock 数据是一件无聊且繁琐的事, 为了一劳永逸, 常常需要做一个 "打桩" 服务(这里的 "打桩" 并不是上海人说的黄牛的意思), 例如做一个永远返回成功的 CALLBACK 服务, 有的甚至可以做一个通过参数调节的智能打桩服务.
端到端测试
端到端测试的重要性: 端到端测试在微服务场合是非常重要的, 它可以保证业务的完整性和性能. 它是指站在最终用户的角度去测试整个微服务流程, 但要实现端到端的测试却非常的困难, 需要整合所有微服务. 这样的测试虽难必行, 只有完成过端到端的测试, 我们才有勇气交付给最终用户.
端到端测试的弊端: 显而易见, 当服务越多, 端到端就越不容易实现. 另外, 谁来写端到端测试用例也是不明确的. 一般按照职责划分团队的公司, 很难有对整个流程都非常清楚的测试人员. 最后, 端到端的测试时间也难以把握.
部署
进入微服务时代后, 最后一个面临的挑战是部署, 传统的部署方式完全无法适应微服务的部署方式. 最主要的问题就在于一台一服务到多台多服务的演变:
如果没有好的部署方式, 用人力部署微服务将是一件万分可怕的事. 所以必须引入无人值守的自动化部署工具.
持续集成
把镜像作为构建物: 很多企业已经习惯于使用虚拟机 vm 来增加物理服务器的利用率. 这样的好处是把操作系统隔离出来, 我们何不再进一步, 把应用和相应的环境配置文件也包含在镜像中, 通过 docker 等容器化技术使部署变得更快. 配置文件打入镜像的好处是避免配置漂移.(配置漂移是指在非常规条件下, 运维人员或开发人员为了修复问题或调试, 手动修改了产线配置文件却忘了恢复, 使得下次发布的 app 和期待的配置不符)
构建 PIPELINE:Pipeline 是 Jenkins2 推荐的自动化构建方式, 微服务可以用其他的方式实现自动化, 只是用 Pipeline 能更清晰的知道每一步在干什么. 下图是沪江微服务发布的一个 Pipeline 截图.
区分部署和上线: 部署和上线是两个感念, 微服务部署完毕并不等于微服务已经上线可用. 它的好处在于在部署到上线之间, 可以接入一些常规测试来避免因为部署或配置等原因导致的线上故障. 入下图所示, 沪江在上线一个微服务的过程中, 引入了蓝绿发布, 既蓝色部分是部署一个微服务到一个产线环境中, 但对外的 LB 并没有指向新部署的程序. 此时可以借助自动化测试脚本或人工黑盒做最基本的测试. 如果测试通过, 既变成绿色部分后, 再把 LB 指向新部署程序上实现上线过程. 整个过程如下图所示.
多服务多服务器的挑战
部署最关键的问题就在于服务多, 服务器也多. 将面临以下问题:
海量的日志:
服务越多, 就越难找到程序的调用链. 如果程序的调用链找不到, 引入服务治理是个好方法. 我们可以在日志中嵌入一些服务治理的信息以打点, 如下图所示, 我们在每个微服务的之中输出了 Trace Id 和 Host IP 等信息, 以方便 ELK 聚合.
要评估某一类服务的服务器占用, 还可以以服务来聚合监控.
日志跟踪与指标跟踪
日志跟踪与指标跟踪的工具大部分是使用 ELK, 它的好处是可以帮我们聚合很多的数据. 还有一个工具就是 mesos metrics, 它是 mesos 自带的一个小工具, 它可以统计出 agent 上应用运行的指标. 它的好处之一是可以帮我们以服务名来聚合运行指标.
对于监控哪些指标, 我们的经验是: 日志是主要的监控指标, 其他还有 cpu,memory 和 disk 等. 这些指标需要以服务名称而不是以物理机来聚合.
监控还能干什么?
我们在应用上线的时候引入 BVT 监控; 并利用监控数据进行自动触发, 实现自动伸缩, 让业务应用更具弹性. 还有就是能对业务进行评价, 通过监控回馈数据的手段来辅助业务和开发分析业务运行和服务运行的健康度.
来源: https://juejin.im/post/5ad35939f265da23906c7657