这书以分布式微服务系统为主线,讲解了微服务架构设计、分布式一致性、性能优化等内容,并介绍了与微服务系统紧密联系的日志系统、全局调用链、容器化等。
还是一样,每一章摘抄一些自己觉得有用的内容,归纳整理,然后加以理解。
第1章 分布式微服务架构设计原理
1. 由传统单体架构到服务化架构
(老生常谈,感觉所有谈到微服务的内容都是从这个角度开始叙述。)
(1)J2EE是二八原则的典型应用场景:它将80%通用的与业务无关的逻辑和流程封装在应用服务器的模块化组件里,通过配置的模式提供给应用程序访问,应用程序实现20%的专用逻辑,并通过配置的形式来访问应用服务器提供的模块化组件。
(2)康威定律
设计系统的组织时,最终产生的设计等价于组织的沟通结构,通俗来说,团队的交流机制应该与架构设计机制相对应。
(3)Java AOP的实现方式有三种
1》对Java字节码进行重新编译,将切面插入字节码的某些点和面上,可以使用cglib库实现
2》定制类加载器,在类加载时对字节码进行补充,在字节码中插入切面,增加了除业务逻辑外的功能,JVM自身提供的Java Agent机制就是在加载类的字节码时,通过增加切面来实现AOP的。
3》JVM本身提供了动态代理组件,可以通过它实现任意对象的代理模式,在代理的过程中可以插入切面的逻辑。可以使用Java提供的APIProxy.newProxyInstance()和InvocationHandler来实现。
(4)在SSH架构里,服务的特点仍然是单体化,服务的粒度抽象为模块化组件,所有组件耦合在一个开发项目中,并且配置和运行在一个JVM进程中。如果某个模块化组件需要升级上线,则会导致其他没有变更的模块化组件同时上线,在严重情况下,对某个模块化组件的变更,由于种种原因,会导致其他模块化组件出现问题。
(5)在微服务架构中,提倡运维人员也是服务项目团队的一员,倡导谁开发、谁维护,实施终生维护制度。
(6)微服务的交互模式
1》读者容错模式
指微服务中服务提供者和消费者之间如何对接口的改变进行容错。该模式就是消费者要对提供者提供的接口做新旧版本的兼容,在读取数据时,采用宽松的校验策略,即尽最大努力提取需要的数据,同时忽略不可识别的数据。
2》消费者驱动契约模式
分为:提供者契约、消费者契约及消费者驱动的契约,它从期望与约束的角度描述了服务提供者与服务消费者之间的联动关系。
3》去数据共享模式
在设计微服务架构时,一定不要共享缓存和数据库等资源,也不要使用总线模式,服务之间的通信和交互只能依赖定义良好的接口。
(7)微服务的粒度
服务要按照业务的功能进行拆分,直到每个服务的功能和职责单一,甚至不可再拆分为止,以至于每个服务都能独立部署,扩容和缩容方便,能够有效地提高利用率。
微服务的拆分原则:拆分到可以让使用方自由地编排底层的子服务来获得相应的组合服务即可,同时要考虑团队的建设及人员的数量和分配等。
见:https://segmentfault.com/a/1190000017547824
从 JEE 到 SSH ,服务的特点仍然是单体化、服务的粒度抽象为模块化组件,所有组件耦合在一个项目中,并配置和运行在一个 JVM 进程中。
为解决上述问题,SOA 出现了:
- SOA 代表面向服务的架构,俗称服务化。
- SOA 将应用程序的模块化组件通过【定义明确的接口和契约】联系起来,接口采用中立的方式进行定义,独立于某种语言、硬件和操作系统。
- SOA 通常通过网络通信来完成,但不局限于某种网络协议,可以是底层的 TCP/IP,也可以是应用层的 HTTP,也可以是消息队列协议,甚至可以是约定的某种数据库存储形式。
SOA:Web Service -> ESB
第2章 彻底解决分布式系统一致性的问题
1.解决一致性问题的模式和思路
(1)酸碱平衡理论
1》ACID(英文意思为酸)
关系型数据库满足ACID特性:Atomicity原子性、Consistency一致性、Isolation隔离性、Durability持久性
2》CAP(帽子原理)
Consistency一致性、Availability可用性、Partition tolerance分区容忍性
CAP原理证明,任何分布式系统只可同时满足以上两点,无法三者兼顾。
3》BASE(英文意思为碱)
Basically Available基本可用、Soft State软状态(状态可以在一段时间内不同步)、Eventually Consistent最终一致
BASE满足CAP原理,通过牺牲一致性获得可用性。系统在进行每步操作时,通过记录每个临时状态,在系统出现故障时可以从这些中间状态继续处理未完成的请求或者退回到原始状态,最终达到一致状态。
2.分布式一致性协议
(1)两阶段提交协议
把分布式事务分为两个阶段:一个是准备阶段(该阶段会锁定资源,是一个重量级的操作),另一个是提交阶段。
(2)三阶段提交协议
通过超时机制解决了阻塞的问题,并将两阶段增加到三阶段:询问阶段(确保尽可能早地发现无法执行操作而需要中止的行为)、准备阶段、提交阶段
(3)TCC
将一个任务拆分成Try、Confirm、Cancel三个步骤。从正常的流程上讲,这仍然是一个两阶段提交协议,但是在执行出现问题时有一定的自我修复能力。
3.保证最终一致性的模式
(1)查询模式
任何服务操作都需要提供一个查询接口,用来向外部输出操作执行的状态。
(2)补偿模式
(3)异步确保模式
将要执行的异步操作封装后持久入库,然后通过定时捞取未完成的任务进行补偿操作来实现异步确保模式。
(4)定时校对模式
(5)可靠消息模式
4.同步与异步的抉择
尽量使用异步来替换同步操作。
能用同步解决的问题,不要引入异步。
第3章 服务化系统容量评估和性能保障
1. 非功能质量需求包括:高可用性、高性能、可伸缩、可扩展、安全性、稳定性、健壮性、可测试性等。
2.性能和容量评估
(1)当前的系统容量(系统调用量的平均值、请求响应时间的平均值等)
(2)当前系统调用量的峰值、最小和最大的请求响应时间
(3)容量评估:按照峰值的5倍进行冗余计算
3.性能测试方案的设计与最佳实践
(1)测试目标要有量化的标准。
对于一个系统,最核心的性能指标莫过于响应时间和吞吐量了。
(2)业务模型分析
这些数据可以根据历史经验和线上数据进行统计。如果是新项目,则需要产品经理根据市场调研的基础数据进行确定。
============================ 继续看下篇 ====================================
《分布式服务架构原理设计与实战》第3章系统容量评估性能保障笔记
核心非功能质量指标
1. 高性能
2. 可用性。持续可用性,宕机时间,出错回复,可靠性
3. 可伸缩性。垂直伸缩,水平伸缩
4. 可扩展性。可插拔,组件重用
5. 安全性。数据安全,加密,熔断,防攻击
非功能质量需求具体指标
1. 应用服务器。负载均衡,高可用模型,I/O模型,线程池
2. 数据库。复制,失效转移,容灾,归档,读写分离,分库分表,静态数据缓存,开了缓存穿透压垮数据库,缓存失效缓存预热。其他指标,索引,有无大数据量查询?,有无多表关联,有无悲观锁,事务和一致性级别。
3. 缓存。复制,失效转移,持久策略,淘汰,线程模型,预热,哈希分片
4. 消息队列。复制,失效转移,持久策略。
典型的技术评审提纲
1. 现状。业务背景和技术背景
2. 需求。业务需求和性能需求
3. 方案描述。概述,详细说明,性能评估,方案的优缺点
中间件架构(应用服务器,数据库,缓存,消息队列)
逻辑结构(模块划分,通信,信息流,时序)
数据架构(数据结构,数据分布,拆分策略,缓存策略,读写分离策略,查询策略,数据一致性策略)
异常处理,容灾策略,灰度发布,上线方案,回滚方案
4. 方案对比
5. 风险评估
6. 工作流评估
容量:按照峰值 5 倍冗余计算
MySQL
单端口读 1000/s
单端口写 700/s
单表容量 5000 万
Redis
读写 40000/s
Kafka 单机 读 30000/s 写 5000/s
然后书上介绍了一些压测工具,ab,jmeter,mysqlslap,sysbench,dd,loadRunner,hprof 等等
《分布式服务架构 原理、设计与实战》综合2
==============================请看上篇===================================
第4章 大数据日志系统的构建
1.日志分类
(1)按产生的来源:系统日志、容器日志、应用日志
(2)按应用目标:性能日志、安全日志
(3)按级别不同:调试日志、信息日志、警告日志、错误日志
2.对于计数器日志、响应时间日志、异常日志,方法入参和返回值等有规律可循的通用日志,可以使用AOP技术的切面编程来打印。
对于业务代码中比较复杂的业务信息,可以直接在代码中打点。
3.Log4j的锁和性能优化
(1)Log4j默认的Appenders使用同步锁来实现,并发时线程都在等待一个写日志事件的锁。
(2)对Log4j进行改进:同步操作改为异步操作,例如可以使用一个缓冲队列,业务线程仅将日志事件放入缓冲队列就返回,然后用单独的消费者线程去消费缓冲队列,异步将缓冲队列的日志内容打印到日志文件。
(3)为了达到较高的性能,使用一个无限循环的线程,批量检查日志缓存队列时是否有日志事件,如果有就批量消费和打印日志。
(4)Disruptor RingBuffer是一个优秀的无锁队列,从设计模式上是观察者模式。
4.Log4j2的异步记录日志功能通过在一个单独的线程里执行I/O操作来提高性能,有两种实现方式:异步Appender和异步Logger。
5. 日志系统的优化和最佳实践
(1)打印日志时必须包含环境信息,例如:用户ID、角色、参数、返回值、逻辑判断结果、循环次数、异常信息等。
(2)必须使用占位符的方式代替字符串连接。
(3)对关键业务步骤必须打点并记录耗时和结果等信息。
(4)Log4j是通过构建异常从异常堆栈中提取方法名、文件名和行号的,需要耗费很多时间和资源。因此,不推荐在日志中使用%L、%M、%F、%l占位符来显示方法名、文件名和行号等,但可以使用%c来打印类名。
(5)toString()方法的实现需要考虑连接字符串是否可能产生NullPointerException,对可能为空的字段先判空后再进行打印。
6. ELK系统
Elasticsearch、Logstash和Kibana
第5章 基于调用链的服务治理系统的设计与实现
1.APM系统
应用性能管理系统,开源的有Pinpoint、Zipkin和CAT。
2.分布式系统的远程调用过程
(1)服务于一个用户请求的内部服务调用结构是一个树型结构
(2)在谷歌的 Dapper论文中,每个节点都对应一个Span,节点之间的连线表示Span和它的父Span之间的关系,具体表现为一次调用请求和响应的调用关系。
(3)通过增加应用层的标记来对服务化中的请求和响应建立联系。例如,它通过HTTP协议头携带标记信息,标记信息包括标识调用链的唯一流水ID(为TraceID),以及标识调用层次和顺序的SpanID和ParentSpanID。
3. TraceID和SpanID在服务间的传递
(1)Java进程内传递
通过ThreadLocal
(2)服务间传递
HTTP方式:请求头增加TraceID和SpanID
RPC方式:在RPC的序列化协议上增加定制化的字段
(3)主子线程间传递
(4)消息队列的传递
在每次发送消息时将TraceID和SpanID增加到消息报文中,在消息队列的处理机的库中先对报文进行解析,再将业务报文传递给应用层处理。
(5)缓存、数据库访问
4. 采集器的实现方法
(1)应用层主动推送
(2)AOP推送
在应用的业务层代码中使用AOP拦截目标服务调用,把请求和响应的调用信息收集后,推送到调用链处理器。
(3)JavaAgent字节码增强
利用JDK提供的java.lang.Instrument API对加载的类进行过滤,找到我们需要增强的目标服务实现类,在相应的方法上增加AOP切面,把服务调用的发送消息和接收信息进行拦截和收集,并发送到调用链处理器上。
(4)代理推送
Kafka消息队列、UDP推送
第6章 Java服务的线上应急和技术攻关
1.海恩法则和墨菲定律
(1)海恩法则
1》事故的发生是量的积累的结果
2》再好的技术、再完美的规章,在实际操作层面也无法取代人自身的素质和责任心
(2)墨菲定律
1》任何事情都没有表面看起来那么简单
2》所有事情的发展都会比你预计的时间长
3》会出错的事总会出错
4》如果你担心某种情况发生,那么它更有可能发生
2.线上应急
(1)6个阶段:
1》发现问题
2》定位问题
3》解决问题
对各种严重情况设计止损和降级开关
4》消除影响
5》回顾问题
类似的问题还有哪些没有想到?
做了哪些事情,这个事故就不会发生?
做了哪些事情,这个事故即使发生了,也不会产生损失?
做了哪些事情,这个事故即使发生了,也不会产生这么大的损失?
6》避免措施
(2)总体目标:尽快恢复问题,消除影响
3. 最小化复现
指在个人开发环境内通过模拟生产环境来重现生产环境产生的问题。
4. 产生OutOfMemoryError(OOM)的原因
(1)java.lang.OutOfMemoryError: Java heap space,表示Java堆空间不足。
(2)java.lang.OutOfMemoryError: PermGen space,表示Java永久代(方法区)的空间不足。
(3)java.lang.OutOfMemoryError: unable to create new native thread,本质原因是创建了太多的线程。
(4)java.lang.OutOfMemoryError: GC overhead limit exceeded,是并行垃圾回收器的GC回收时间过长、超过98%的时间用来做GC并且回收了不到2%的堆内存时抛出的异常
5. 使用Dubbo服务框架时,采用自动降级原则,如果Dubbo服务负载增加或者注册中心宕机,则会自动切换到点对点的RPC框架。
============================= 继续看下篇==================================
《分布式服务架构 原理、设计与实战》综合3
================================== 请看上篇 ===================================
第7章 服务的容器化过程
1.容器和虚拟化的区别
(1)容器是对应用层的抽象,它把应用程序的代码和相关依赖打包在一起执行,多个容器可以在同一台物理机上互不影响地独立运行,并且共享操作系统内核,启动非常快,占用的空间非常少,一般也就十几兆。
(2)而虚拟机是在物理硬件层上的虚拟化,每台虚拟机必须包括一整套操作系统、应用程序和各种依赖库等,启动非常慢,占用的空间为GB级别。
2. Docker将集装箱思想运用到对软件的打包上,为代码提供了一个基于容器的标准化运输系统,可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器,可以运行在几乎所有操作系统上。
第8章 敏捷开发2.0的自动化工具
1.常用的4种开发模式
(1)瀑布式开发
(2)迭代式开发
工作可以在需求被完整地确定之前启动,并在一次迭代中完成系统的一部分功能或业务,再通过客户的反馈来细化需求,并开始新一轮的迭代。
(3)螺旋式开发
引入了风险分析
(4)敏捷软件开发
更注重软件开发过程中人的作用
2. DevOps
(1)更是一种文化的改变和鼓励沟通、交流、合作的行动,目的在于更加快速稳定地沟通高质量的应用系统。
(2)体现了精益管理的原则。
(3)DevOps也是一种能力:全局观、自动化
(4)DevOps可用一个公式表达:
文化观念的改变 + 自动化工具 = 不断适应快速变化的市场
其核心价值在于:
1》更快速地交付,响应市场的变化
2》更多地关注业务的改进与提升
3.敏捷开发
(1)持续集成(Continuous Integration,CI)和持续交付(Continuous Delivery,CD)
(2)养成测试驱动开发(Test-Driven Development,TDD)的习惯
当流程出错而中断时,必须第一时间去修复问题
========================== END ==========================