第一章 单块架构及其面临的挑战
经典的三层架构:
表示层:聚焦数据显示和用户交互;
业务逻辑层:聚焦业务逻辑处理;
数据访问层:聚焦数据的存储和访问。
传统的单块架构应用的表现:
功能集中、代码和数据中心化、一个发布包(对java应用而言,一般是war或者ear包)、部署后运行在同一个进程的应用程序。
扩展性分:
水平扩展性:horizontal scaling,scale-out,通常做法是建立一个集群通过在集群中不断添加新节点,然后借助于前端的负载均衡器,将用户的请求按照某种算法,轮转法、散列法或者最小连接法等合理地将请求分配到不同的节点上。
垂直扩展性,vertical scaling,scale-up,适用于扩展要求紧急的情况,即通过购买性能更高的服务器,存储量过大,性能更好的数据库等等。
内存密集型的应用程序,需要缓存大量数据;
CPU密集型的应用程序,需要进行大量计算;
康威定律:一个组织的设计成果,其结构往往对应于这个组织的沟通结构。
第二章:微服务架构综述
微服务架构是一种架构模式,提倡将单一应用程序划分一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的restful API)。每个服务都围绕着具体业务进行构建,并且能够被独立部署到生产环境、类生产环境。应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下午,选择合适的语言、工具对其进行构建。
Martin·Fowler
康威生命游戏:
微服务的“微”,见仁见智。最重要的是团队对其的打磨,但是最少还是要满足以下两个基本前提:
业务独立性:关于业务建模和划分,参考Eric Evans的《领域驱动模型》
团队自主性:人数不过10人,考虑到沟通协作成本;功能齐全,前后端,测试运维等。
SRP(single responsibility principle)单一职责原则。
Java RMI或者.NET Remoting,虽然可以使用RPC的方式来简化消费者端的调用,使得消费者一端像调用本地接口一样调用远端接口,而丝毫没有觉知,但是最大的劣势是:对于语言或者平台的强耦合性,灵活性和可扩展性差。举例,如果使用java的rmi作为通信协议,则通信的两端必须采用运行在JVM之上的开发语言实现。
精益创业(Lean startup)通过迭代持续改进,帮助组织分析并建立最小可实行产品(Minimum Viable Product);敏捷方法帮助组织消除浪费,通过反馈不断找到正确的方向;持续交付(CD)帮助组织构建更快、更可靠、可频繁发布的交付机制;云、虚拟化和基础设施自动化(Infrastructure As Code)的使用则极大简化基础设施的创建、配置以及系统的安装和部署;DevOps文化的推行更是打破传统开发与运维的壁垒,帮助组织形成全功能化的高性能团队。
同传统的虚拟化技术相比,基于容器技术的docker,不需要额外的hypervisor机制的支持,性能更好,效率更高。
SOA的提出,目的是解决企业内部不同IT资源之间无法互联而导致的信息孤岛问题。
ESB(enterprise service bus)、webservice、SOAP等技术的出现,才使得SOA逐渐落地。
SOA与微服务的区别:
SOA实现 | 微服务架构实现 |
企业级,自顶向下开展实施 | 团队级,自底向上开展实施 |
服务由多个子系统组成,粒度大 | 一个系统被拆分成多个服务,粒度细 |
企业服务总线,集中式的服务架构 | 无集中式总线,松散的服务架构 |
集成方式复杂(ESB/WS/SOAP) | 集成方式简单(HTTP/REST/JSON) |
单块架构系统,相互依赖,部署复杂 | 服务能够独立部署 |
微服务的本质特征包括但不限于:
服务作为组件;围绕业务组织团队;关注产品而非项目;技术多样性;业务数据独立;基础设施自动化;演进式架构(目的是业务驱动架构,架构服务于业务)。
微服务结构提倡服务自主管理其相关的业务数据,优势:
- 能够随着业务的发展,提供业务数据集成接口,而不是以数据库的方式同其他服务集成;
- 能够随着业务的发展,选择更适合的工具管理或者迁移业务类数据。
在一个复杂的后台CRM系统中,产品数据的种类繁多,更新比较频繁,可以使用类似MongoDB这种文档数据库,可以灵活地根据需求动态调整结构;
对于用户访问系统时产生的会话信息,可以使用Redis等键值系统;
报表数据的结构变化不大,要求数据的高一致性,可以使用传统的关系型数据库。
微服务的缺陷:
分布式调用比进程内调用更耗时,严重依赖于网络可靠性和稳定性;
第三章 构建第一个微服务
REST以资源为中心,将外部访问的所有信息定义成不同的资源,并使用HTTP的方法,映射为操作资源的行为。
第四章 Hello world API
对于ruby语言不熟。
第五章 构建docker镜像
Boot2docker工具,在Mac系统搭建docker运行环境。
DockerHub 关联GitHub代码库(主要是指Dockerfile所在目录)
由于在公司接触这一块半年多,很熟悉,没啥可以记录的。
第六章 部署docker镜像
基础设施自动化的优势,在于将传统认为最耗时、最麻烦、最容易出错的环境安装、配置过程采用代码的方式自动化起来。这类工具包括:chef、puppet、ansible以及salt。
AWS EC2节点提供持久性存储卷Amazon EBS(elastic block store),更多EC2的使用以及配置值得学习。
AWS CloudFormation作为部署和运行docker的基础设施,EC2节点运行docker容器。
第七章 持续交付流水线
书中使用的CI服务器是该书作者所在公司ThoughtWorks自家的在线CI工具snap-ci,已停止服务;没有继续研究阅读章节的需要。类似的CI服务器是,大多数GitHub开源项目使用的CI工具,Travis-CI。
大多数持续集成服务器,都可以通过WebHook的方式,检测到代码块的提交事件,并触发相应的处理机制。
语义化版本,对于一个给定的版本号,将其定义为MAJOR.MINOR.PATCH(主·次·补丁)的形式:
MAJOR:在API发生不可向下兼容的改变时使用(增加);
MINOR:在有向下兼容的新功能加入时增加;
PATCH:在有向下兼容的缺陷被修复时增大。
第八章 日志聚合
日志聚合工具,商业版有Splunk(也有功能受限的免费版,最主要的差别是每天的索引容量大小,索引是搜索功能的基础),开源版有ELK。
Splunk的主要功能:
日志聚合;日志搜索;语义提取;对结果进行分组、联合、拆分和格式化;强大的可视化功能;电子邮件提醒功能。
Splunk可以单机,集群安装部署。
主要包括三个部分:
数据采集转发器:采集数据,Splunk可以实时监控文件或者目录的变化,可以从标准输出、网络程序中收集数据。
数据索引器:数据存储,并采用高效的索引方式对日志进行索引。
搜索分析和可视化:通过Splunk处理语言,提供搜索,过滤功能,还有展示功能
LogStash,JRuby实现,功能包括:
日志收集:LogStash可以从多个数据源获取日志,如标准输入,日志文件,syslog;内嵌支持多种日志的格式,如系统日志,web服务器日志,错误日志,应用日志。如果日志的输入是syslog,则用户不需要在每台服务器安装日志代理(log agent),默认的rsyslog客户端就可以直接同步日志。
日志过滤:grep、split、multiline。
结果输出:内置Web UI,不过一般是和Kibana集成使用,Kibana作为展示工具。
第九章 监控与告警
业界的监控产品,如:Ganglia、Zabbix、NewRelic、Nagios、OneAPM;以Nagios为例。结构上分成两部分:Nagios核心和插件。支持的功能包括:
监控网络服务,包括但不限于SMTP、POP3、HTTP、FTP、PING等;
监控主机资源,如CPU负荷,磁盘利用率;
自定义插件,插件开发语言支持多种语言;
告警通知;
提供web界面;
工作原理:需要一个监控中心,对于每台需要被监控的节点(主机或者服务),需要运行一个与监控中心服务器进行通信的Nagios代理(agent);中心服务器读取配置文件中的指令,然后与远程的Nagios代理程序通信,并指示远程的代理程序进行检查。核心部分必须安装在类UNIX系统,远程监控节点没有限制。
通信方式,有主动检测(监控中心向代理发起请求,代理应答)和被动检测(代理将检测状态发给监控中心)两种。
Nagios安装
参考官网,目录解释,以及配置文件,具体需要使用时再查文档;
配置包括主机、服务、联系人、 监控时间、监控命令
告警,更专业的工具如PagerDuty。
第十章 功能迭代
数据的存储比较简单是使用CRUD即可;对于复杂的情况,需要考虑安全性、读写比。可伸缩性,此时考虑使用命令查询职责分离CQRS(command query responsibility segration)
第十一章 微服务与持续交付
交付过程的发展历程:RUP模型、敏捷、XP、Scrum、精益创业、DevOps。
持续交付的核心:小批量的需求、较短的周期、小粒度的频繁发布。频繁交付的优势:持续为用户提供价值,产生快速的反馈(闭环),及时调整发布策略等。总结下来:小、频、快。
从开发角度来看,代码库独立(即,每个服务对应一个且只有一个独立的代码块URL)有助于持续交付。
服务说明文件,用于描述当前服务的信息,功能说明。笔者的实践,服务说明包括如下几个部分:
- 服务介绍:提供什么服务、服务消费者是谁
- 服务维护者:姓名邮件等
- 服务可用期:服务可用期、可用率、响应时间
- 定义环境:生产、类生产、测试等
- 开发信息:如何搭建开发环境、如何运行服务、如何定位问题
- 测试信息:测试策略、如何运行测试、如何查看测试统计结果(覆盖率,运行时间,性能)
- 集成&构建信息:CI访问的URL、CI的流程描述、构建后的部署包
- 部署信息:如何部署到不同的坏境、部署后的功能验证
- 运维信息:日志聚合、告警信息、监控信息的访问
git clone下来的代码应该可以低成本运行。如果需要依赖于外部资源,就应该考虑其他打桩的机制来模拟这些外部资源(数据库、云存储、缓存、第三方系统等)。
对于单元测试而言,可以使用Mock框架来完成对依赖的模拟Mock或者打桩Stub,参考Martin·Fowler的《Mocks aren’t stubs》。
行为测试框架,如cucumber、JBehave。通常是在最外层(即不是服务,而是整个应用)做一部分行为测试。一般不对服务做行为测试的原因:
- 一般而言,服务不涉及用户体验部分;服务更关注的是数据的变化,而不是同用户的交互过程;
- 服务已经有单元测试和接口测试;
- 测试金字塔,行为测试的成本大,反馈周期长。
- IaaS平台,如Amazon的AMI;
如何部署可以考虑的两个维度:部署环境;部署方式。
云平台,包括三层IaaS、PaaS、SaaS;SaaS是相对于应用的使用者而言的,软件即服务。公有云指运行在Internet上的云服务,私有云主要是指运行在企业内部Intranet的云服务;
监控通常分为两类,系统监控和应用监控;前者关注服务运行所在节点的健康状况,如CPU、内存、磁盘、网络;后者则关注应用本身及其相关依赖的健康状况,如服务的可用性、依赖服务的可用性;
第十二章 微服务和轻量级通信机制
12.1 同步异步通信
同步通信:客户端(consumer或者消费者)发出请求后,在服务端(Provider或者生产者)处理未结束前,客户端一直处于等待状态,直到最终获得对端的响应。实现简单,会造成阻塞操作;
异步通信:客户端发出请求后,服务端或者第三方组件会先接受消息并应答,然后在合适的时间对请求进行处理;此时,客户端不需要一直处于等待状态。不会阻塞,实现比较复杂,问题出现时,不容易定位问题、调试问题。适合耗时操作。
12.2 远程调用
远程调用RPC,远程过程调用
一种分布式节点间同步通信的实现方式;客户端通过客户代理存根(Stub),传递函数参数,想服务端发起函数调用。服务器端通过服务器代理存根(Skeleton),接受到客户端的请求后,对请求进行处理,并在结束后想客户端返回响应,完成一次通信。
远程方法调用RMI,remote method invocation,是远程过程调用的一种面向对象的实现。如java RMI,Thrift,protocol buffers。
12.3 REST
分布式节点见同步通信的实现方式。之所以说是同步,因为REST基于HTTP,而HTTP的通信是同步过程,当然可以使用AJAX等方式将通信的过程异步化。REST的四个关键部分:
URI仅代表资源resources的实体,表述是在HTTP请求的头信息中用Accept和Content-Type来指定。POST新建资源;PUT更新资源。
REST的不足/挑战:
- 如何标准化资源结构;
- 如何处理资源的相关链接。
关于第二点,一般是以JSON作为传输格式,但是如W3C所述:
“JSON has no built-in support for hyperlinks, which are a fundamental building block on the web.”
用户资源的JSON数据应该可以自解释资源的关联关系。
其他: - 性能:REST基于HTTP,HTTP是基于TCP/IP的应用层协议,故而REST不是低延时通信的最好选择。
- 开发成本:以JSON作为默认的请求响应资源,那么需要编写代码来解析,有库的支持。
12.4 HAL
Hypertext application language,轻量级超文本应用描述协议,基于REST,解决上述REST的两个核心问题。
HAL中的资源分成三个标准的部分:
状态state:资源本身固有的属性;
链接links:与当前资源相关的一组资源的链接的集合,包括链接名称、目标URI、访问URI的参数;
子资源Embedded resources:在当前资源的内部,其嵌套资源的定义。
HAL浏览器。12.5 消息队列
节点间异步通信;消息队列的核心:
其中安全策略,决定哪些接收者能够访问或者获取消息。
消息队列的访问,拉模式和推模式:推模式意味着发布者、消费者以及队列必须依赖语言或者平台的某些特性,依赖性较强;如RabbitMQ基于AMQP协议,ActiveMQ基于JMS协议。12.6 后台任务处理系统
常用的系统如Resque、Sidekiq、Delayed_job,核心部分:
不常用?没有深入细看。
总结:
第十三章 微服务与测试
微服务结构:
其中,模型存储(repository)关注如何存储或者获取业务数据。与场景有关,关系型数据库适合存储结构化信息,NoSQL适合存储非结构化信息,文件系统适合存储文本信息,云存储(Amazon S3)适合存放静态资源。最大优势在于屏蔽数据存储的获取的实现细节,让调用者更关注接口而非实现。微服务的测试策略:
单元测试;
接口测试;
集成测试;
组件测试;
端到端测试。
从下往上,业务价值比重逐渐增加,测试越能体现业务价值,测试成本也在增加。从顶往下,测试的效率逐渐提高,反馈周期逐渐缩短,执行效率更高。
集成测试,实施起来,两种方向:自顶向下(top-down Integration,与测试驱动开发BDD类似),自底向上(bottom-up integration)。
契约测试。没有细看。
组件测试,进程内测试,进程外测试。
端到端测试。
第十四章 使用微服务架构改造遗留系统
改造策略:
最小修改;
功能剥离;
数据解耦;
数据同步;
迭代替换。
ETL(extract、transform、load)
公司内部形成的微服务开发模版,包括四部分:快速开发模版、代码生成工具、持续集成模版、一键部署工具(如Netflix的Asgard工具,开源,GitHub有)。Ruby里面不管。类似的话,java里面就有大名鼎鼎的spring boot。