架构师的36项修炼
2024-04-10 16:06:01 0 举报
AI智能生成
架构师的36项修炼
作者其他创作
大纲/内容
架构核心之分布式消息队列
介绍
同步架构和异步架构的区别
异步架构的主要组成部分:消息生产者、消息消费者、分布式消息队列。异步架构的两种主要模型:点对点模型和发布订阅模型。
分布式消息队列异步架构的优点
异步处理实现快速响应;消费者易于伸缩;
高并发访问压力的时削峰填谷,减轻访问高峰的系统负载压力;
隔离失败任务,消费者处理任务失败,不会影响业务流程;
业务逻辑解耦,系统易于开发和维护
高并发访问压力的时削峰填谷,减轻访问高峰的系统负载压力;
隔离失败任务,消费者处理任务失败,不会影响业务流程;
业务逻辑解耦,系统易于开发和维护
同步调用与异步调用
同步调用
从请求的发起一直到最终的处理完成期间,请求的调用方一直在同步阻塞,等待调用的处理完成
异步调用
客户端的调用,也就是应用程序的调用,和业务逻辑真正发送邮件的操作是不同步的
消息队列构建异步调用架构
消息生产者
创建一个合法的消息,并把这个消息发送到消息队列中
消息队列
消息队列是消息发送的目的地,也是发给消费者过程中的一个缓冲
消息消费者
从消息队列中接收并处理消息,也是由应用开发者实现的,但是一个异步处理的组件
模型
点对点模型(针对队列)
生产者发送消息到消息队列中,而消息队列的另一端是多个消费者竞争消费消息,每个到达消息队列的消息只会被路由到一个消费者中去
发布订阅模型(针对主题)
生产者发送消息到一个主题,而不是队列中。消息被发布到主题后,就会被克隆给每一个订阅它的消费者,每个消费者接收一份消息复制到自己的私有队列
两种模型对比
使用点对点模型
给用户发送邮件业务(只需要一个业务端处理)
发送邮件,应用程序其实并不太关心邮件发送是否成功,它只需要把邮件消息丢到消息队列中就可以返回了。消费者只需要把邮件消息内容取出来以后进行消费,通过远程服务器将邮件发送出去就可以了。
发送邮件,应用程序其实并不太关心邮件发送是否成功,它只需要把邮件消息丢到消息队列中就可以返回了。消费者只需要把邮件消息内容取出来以后进行消费,通过远程服务器将邮件发送出去就可以了。
使用发布订阅模型
新用户注册(多个业务要消息这个消息)
一个新用户注册成功以后,需要给用户发送一封激活邮件,发送一条欢迎短信,还需要将用户注册数据写入数据库,甚至需要将新用户信息发送给关联企业的系统
一个新用户注册成功以后,需要给用户发送一封激活邮件,发送一条欢迎短信,还需要将用户注册数据写入数据库,甚至需要将新用户信息发送给关联企业的系统
消息队列的好处
异步处理
实现异步处理,提升处理性能。
不必阻塞客户端的程序,客户端的程序在得到处理结果之前就可以继续执行,从而提高客户端程序的处理性能
不必阻塞客户端的程序,客户端的程序在得到处理结果之前就可以继续执行,从而提高客户端程序的处理性能
易伸缩
让系统获得更好的伸缩性。
很容易地添加更多的机器成为消费者
很容易地添加更多的机器成为消费者
使峰值平缓
使用消息队列,即便是访问流量持续的增长,系统依然可以持续地接收请求。这种情况下,虽然生产者发布消息的速度比消费者消费消息的速度快,但是可以持续地将消息纳入到消息队列中,用消息队列作为消息的缓冲,因此短时间内,发布者不会受到消费处理能力的影响。
失败隔离及自我修复
分布式消息队列可以将消费者系统产生的错误异常与生产者系统隔离开来,生产者不受消费者失败的影响
解耦
使生产者和消费者的代码实现解耦合,也就是说可以多个生产者发布消息,多个消费者处理消息,共同完成完整的业务处理逻辑
从消息生产者的视角看,它只需要构建消息,将消息放入消息队列中,开发就完成了;而从消费者的开发视角看,它只需要从消息队列中获取消息,然后进行逻辑处理。它们彼此之间不进行任何耦合
消息队列相关挑战
消息无序
生产者会创建两个消息,一个是创建用户,另一个是欢迎邮件。消费者应该先消费创建用户,然后再消费欢迎邮件,业务逻辑有先后顺序。实际上并行处理时可能会倒序处理。
解决方案
1. 使用同一个字段来标识要发送到同一个队列
2. 先处理完创建用户,再发送欢迎邮件
3. 发现倒序后,可以先存入异常数据库,再走定时任务处理
1. 使用同一个字段来标识要发送到同一个队列
2. 先处理完创建用户,再发送欢迎邮件
3. 发现倒序后,可以先存入异常数据库,再走定时任务处理
消息重新入队列
分布式消息队列产品支持将某个消费者处理失败的消息重新放入到消息队列中,被其它的消费者重新处理
解决方案
1. 设置处理记录幂等性
1. 设置处理记录幂等性
竞态条件
消息队列可以在分布式的环境下实现架构层面的并发执行,并发执行就可能会导致对资源的争用。在编程中我们通常使用锁的机制进行并发的控制,以避免竞态、顺序执行
复杂度风险
消息队列使系统的架构和处理流程更加复杂,带来了更多的复杂性问题,从而也对架构师的系统架构设计能力和架构把控能力提出了更高的挑战和要求
消息队列的反模式
阻塞式调用
有些分布式消息队列产品允许生产者阻塞,也就是生产者发送消息以后,阻塞等待消息队列处理结果,等消费者处理完成返回处理结果以后,继续向下执行
耦合生产者和消费者
在消息中包含处理逻辑,也就是说在消息中约定消费者应该如何进行处理。或者是说使用特定的序列化协议编码消息。那么消费者必须要按照特定的序列化格式,才能解码消息。这些情况都使得生产者和消费者产生了不必要的耦合。
缺少坏消息处理
使用消息队列的时候,不能总是假定消息永远正确。对于引发消费者崩溃的消息,应该丢弃而不是重新处理
常用消息队列产品
RabbitMQ 的主要特点是性能好,社区活跃,但是 RabbitMQ 用 Erlang 开发,我们的应用很少用 Erlang,所以不便于二次开发和维护。
ActiveMQ 影响比较广泛,可以跨平台,使用 Java 开发,对 Java 开发者比较友好。
RocketMQ 是阿里推出的一个开源产品,也是使用 Java 开发,性能比较好,可靠性也比较高。
Kafka 是 Linkedin 出品的,专门针对分布式场景进行了优化,因此分布式的伸缩性会比较好。
ActiveMQ 影响比较广泛,可以跨平台,使用 Java 开发,对 Java 开发者比较友好。
RocketMQ 是阿里推出的一个开源产品,也是使用 Java 开发,性能比较好,可靠性也比较高。
Kafka 是 Linkedin 出品的,专门针对分布式场景进行了优化,因此分布式的伸缩性会比较好。
架构核心技术之分布式数据存储
数据库复制
主从复制
实现数据库读写分离——写操作访问主数据库,读操作访问从数据库,从而使数据库具有更强大的访问负载能力,支撑更多的用户访问
复制原理
复制原理是当应用程序客户端发送一条更新命令到数据库的时候,数据库会把这条更新命令同步记录到 Binlog 中,然后由另外一个线程从 Binlog 中读取这条日志,再通过远程通讯的方式将它复制到从服务器上面去,从服务器获得这条更新日志后,将其加入到自己的 Relay log 中,然后由另外一个 SQL 执行线程从 Relay log 中读取这条新的日志,并把它在本地的数据库中重新执行一遍,这样当客户端应用程序执行一个 update 命令的时候,这个命令会在主数据库和从数据库上同步执行,从而实现了主数据库向从数据库的复制,让从数据库和主数据库保持一样的数据
一主多从复制
优点
分摊负载
将只读操作分布在多个从数据库上,从而将负载分摊到多台服务器上。
使用更多的从数据库向应用程序提供读服务,更好地减轻了整个数据库的访问压力。
使用更多的从数据库向应用程序提供读服务,更好地减轻了整个数据库的访问压力。
专机专用
可以针对不同类型的查询,使用不同的从服务器。
比如有一台服务器专门用来做应用程序的读操作,另一个服务器专门用来执行数据报表类的操作,还有的服务器可能专门执行数据备份
比如有一台服务器专门用来做应用程序的读操作,另一个服务器专门用来执行数据报表类的操作,还有的服务器可能专门执行数据备份
便于冷备
使用一主多从的复制就就可以实现零停机时间的备份。只需要关闭数据的数据复制进程,文件就处于关闭状态了,然后进行数据文件拷贝,拷贝完成后再重新打开数据复制就可以了。
高可用
如果一台服务器宕机了,只要不发请求给这台服务器就不会出问题。当这台服务器恢复的时候,再重新发请求到这台服务器。所以,在一主多从的情况下,某一台从服务器宕机不可用,对整个系统的影响是非常小的。
主主复制
主主复制方案是指两台服务器都当作主服务器,任何一台服务器上收到的写操作都会复制到另一台服务器上。
当客户端程序对主服务器 A 进行数据更新操作的时候,主服务器 A 会把更新操作写入到 Binlog 日志中,然后 Binlog 会将数据日志同步到主服务器 B,写入到主服务器的 Relay log 中,然后执行 Relay log,获得 Relay log 中的更新日志,执行 SQL 操作写入到数据库服务器 B 的本地数据库中
当客户端程序对主服务器 A 进行数据更新操作的时候,主服务器 A 会把更新操作写入到 Binlog 日志中,然后 Binlog 会将数据日志同步到主服务器 B,写入到主服务器的 Relay log 中,然后执行 Relay log,获得 Relay log 中的更新日志,执行 SQL 操作写入到数据库服务器 B 的本地数据库中
MySQL 复制的注意事项
不要对两个数据库同时进行数据写操作,因为这种情况会导致数据冲突。
复制只是增加了数据的读并发处理能力,并没有增加写并发的能力和系统存储能力。
更新数据表的结构会导致巨大的同步延迟。
不要对两个数据库同时进行数据写操作,因为这种情况会导致数据冲突。
复制只是增加了数据的读并发处理能力,并没有增加写并发的能力和系统存储能力。
更新数据表的结构会导致巨大的同步延迟。
数据分片
数据分片的目标
将一张数据表切分成较小的片,不同的片存储到不同的服务器上面去,通过分片的方式使用多台服务器存储一张数据表
数据分片的特点
分片的主要特点是数据库服务器之间互相独立,不共享任何信息,即使有部分服务器故障,也不影响整个系统的可用性。
通过分片键进行路由分区算法计算,查询对应的服务器
通过分片键进行路由分区算法计算,查询对应的服务器
数据分片的原理与实现
用刚才提到的分片键的路由算法。通过分片键,根据某种路由算法进行计算,使每台服务器都只存储一部分数据
映射关系存储在外面
根据数据定位自己要连接哪个服务器
根据数据定位自己要连接哪个服务器
当我们执行一个查询操作“select * from orders where prov='wuhan'”的时候,Mycat 会根据分片规则将这条 SQL 操作路由到 dn1 这个服务器节点上。dn1 执行数据查询操作返回结果后,Mycat 再返回给应用程序
分片数据库的伸缩扩容
将数据库切分成 32 个逻辑数据库,但是开始的时候只有两个物理服务器,我们把 32 个数据库分别启动在两个物理服务器上面。那么,路由算法就还是按照 32 进行路由分区,数据分片也是 32 片。当两台服务器不能够满足数据存储和访问要求的时候,我们只需要简单地将这些逻辑数据库迁移到其他的物理服务器上就可以完成扩容。因为迁移后数据分片还是 32 片,数据分片的算法不需要改变。数据迁移也仅仅是将逻辑数据库迁移到新的服务器上面去,而这种迁移通过数据库的主从复制就可以完成。
数据库部署方案
单一服务和单一数据库
主从复制
通过主从复制,实现一主多从。应用服务器的写操作连接主数据库,读操作从从服务器上进行读取
业务分库
数据的业务分库是一种逻辑上的,是基于功能的一种分割,将不同用途的数据表存储在不同的物理数据库上面去
综合部署
更复杂的综合部署方案,则是根据不同数据的访问特点,使用不同的解决方案进行应对。比如类目数据库,也许通过主从复制就能够满足所有的访问要求,但是如果用户量特别大,进行主从复制或主主复制,还是不能够满足数据存储以及写操作的访问压力,这时候就可以对用户数据库进行数据分片存储了,同时每个分片数据库也使用主从复制的方式进行部署
NoSQL数据库
CAP原理与数据一致性
对于一个分布式系统,它不能够同时满足一致性(C)、可用性(A)以及分区耐受性(P)这三个特点。
一致性是说,任何时候集群中所有的数据的备份都是一致的;
可用性是说,当分布式集群中某些服务器节点失效的时候,集群依然是可用的;
分区耐受性是说所当网络失效的时候,节点无法通信的时候,系统依然是可用的。
而 CAP 原理就是说这三者无法同时满足
一致性是说,任何时候集群中所有的数据的备份都是一致的;
可用性是说,当分布式集群中某些服务器节点失效的时候,集群依然是可用的;
分区耐受性是说所当网络失效的时候,节点无法通信的时候,系统依然是可用的。
而 CAP 原理就是说这三者无法同时满足
一致性冲突解决方案
解决一致性冲突的方案就是实现最终一致性。
不同服务器上存储的同一个数据可能是不一致的,但是它最终还是一致的,只要不一致的时间不影响应用程序的正确性,我们就是可以接受的,这种一致性叫作最终一致性。
不同服务器上存储的同一个数据可能是不一致的,但是它最终还是一致的,只要不一致的时间不影响应用程序的正确性,我们就是可以接受的,这种一致性叫作最终一致性。
高性能系统架构设计
性能测试
性能测试是性能优化的提前和基础,也是性能优化结果和度量标准。
优化必须了解系统。
系统的架构是什么样子的?系统的关键技术点、瓶颈点在哪里?为何会产生这样的瓶颈点?以及如何对它进行优化?必须要在了解系统的基础之上才能进行优化。所以性能测试以及了解系统,是性能优化的两个关键前提。
系统的架构是什么样子的?系统的关键技术点、瓶颈点在哪里?为何会产生这样的瓶颈点?以及如何对它进行优化?必须要在了解系统的基础之上才能进行优化。所以性能测试以及了解系统,是性能优化的两个关键前提。
性能标准有主观和客观两种视角
主观
主观标准是说使用者在体验上的快慢,用户在使用系统的时候,它主观上感觉快还是慢,那么就会得到一个性能好还是差的主观标准;
客观
客观标准,也就是在客观上性能指标到底是好还是差。
性能优劣的指标主要有响应时间、并发数、吞吐量以及性能计数器
响应时间
应用系统从发出请求开始到收到最后响应数据所需要的时间
并发数
并发数是指系统同时处理的请求数,这个数字反映了系统的负载特性
吞吐量
单位时间内系统处理请求的数量,体现的是系统的处理能力
吞吐量、响应时间和并发数三者之间是有关联性的,响应时间足够快,那么单位时间的吞吐量也会相应的提高。比如说响应时间如果是 100ms,对于一个并发用户,并发数是 1,那么 TPS 就可以是 10。如果响应时间是 500ms,用户并发数还是 1,那么 TPS 吞吐量就变成了 2。
性能计数器
系统负载 System Load、对象和线程数、内存使用、CPU 使用、磁盘和网络 I/O 使用等指标。
这些指标是系统监控的重要参数,反映系统负载和处理能力的一些关键指标,通常这些指标和性能是强相关的。
这些指标很高,成为瓶颈,通常也预示着性能可能会出现问题。在实践中会对这些性能指标设置一些报警的阈值。当监控系统发现性能计数器超过阈值的时候,就会向运维和开发人员报警
这些指标是系统监控的重要参数,反映系统负载和处理能力的一些关键指标,通常这些指标和性能是强相关的。
这些指标很高,成为瓶颈,通常也预示着性能可能会出现问题。在实践中会对这些性能指标设置一些报警的阈值。当监控系统发现性能计数器超过阈值的时候,就会向运维和开发人员报警
性能测试方法
性能测试
对系统不断施加压力,验证系统在资源可接受的范围内是否达到了性能的预期
负载测试
对系统不断施加并发请求,增加系统的压力,直到系统的某项或多项指标达到安全临界值。
负载测试是指通过不断施加负载压力,寻找系统最优的处理能力,最好的性能状态,达到最大的性能指标
负载测试是指通过不断施加负载压力,寻找系统最优的处理能力,最好的性能状态,达到最大的性能指标
压力测试
是指在超过安全负载的情况下,对系统继续施加压力,直到系统崩溃,或者不再处理任何请求,以此获得系统的最大压力承受能力。
稳定性测试
指被测试的系统在特定的硬件、软件和网络环境条件下,给系统施加一定的业务压力,使系统运行较长一段时间,以此检测系统是否稳定。为了更好地模拟生产环境,稳定性测试也应该不均匀地对系统施加压力,看系统在这种持续的、长时间的、不均匀的访问压力之下,能否稳定地提供响应特性,系统性能是否保持稳定。
性能特性曲线
横轴是系统资源或者并发用户数,对于性能测试,系统资源和并发用户数本质上是一样的,因为随着并发用户数的增加,系统资源消耗是线性增加的。纵轴是它的吞吐量 TPS。
1. 性能测试:在性能测试阶段,随着并发访问逐渐的增加,系统资源的不断消耗,TPS 是在不断上升的。
2. 负载测试:到了负载测试阶段,这种上升的斜率会变小,直到达到了系统负载能力的最大点,也就是 c 点。
3. 压力测试:而过了 c 点以后继续施加压力,继续提高并发请求的数量,系统资源消耗进一步增加,TPS 吞吐量不增反降,会呈现下降趋势。直到到达了某个点,d 点,系统超过了它的最大承受能力,系统崩溃
2. 负载测试:到了负载测试阶段,这种上升的斜率会变小,直到达到了系统负载能力的最大点,也就是 c 点。
3. 压力测试:而过了 c 点以后继续施加压力,继续提高并发请求的数量,系统资源消耗进一步增加,TPS 吞吐量不增反降,会呈现下降趋势。直到到达了某个点,d 点,系统超过了它的最大承受能力,系统崩溃
响应时间特性曲线
随着并发用户数的增加,以及系统资源的不断消耗,系统的响应时间在不断增加。在性能测试阶段,系统的响应时间几乎没有太多的变化,但是到了负载测试的时候,系统的响应时间就开始增加,当超过了它最大负载点——c 点以后继续增加压力,系统的响应时间会急剧增加,系统的性能状况急剧恶化,最后到达了它的崩溃点——d 点
一般说来,性能测试是通过增加并发数,不断测试各项性能指标获得的。如下图性能测试结果表所示,并发数不断地增加,响应时间也不断地增加,TPS 先增加后下降,而错误率超过了某些点以后开始增加,后来增速加剧,同时系统的负载也在不断增加。
系统性能优化
分层优化系统性能
硬件优化
第一层是机房与骨干网络的性能优化
主要手段就是采用异地多活的多机房架构。为了联通这些异地多活的多机房架构,会建设自己专用的骨干网络,并且自主进行 CDN 建设
第二层是对服务器内的硬件进行优化
使用垂直伸缩,提高服务器硬件的性能,对系统性能的提升会有很大的好处。
大量时间消耗在网络传输上,且网卡的读写传输能力已达到极限
Spark 是一个大数据处理平台,所以需要处理大量的数据,在作业处理过程中,不同的服务器之间需要传输大量的数据。经过性能指标分析,我们发现,在一次作业运行中,大量的时间消耗在网络传输上。
Spark 是一个大数据处理平台,所以需要处理大量的数据,在作业处理过程中,不同的服务器之间需要传输大量的数据。经过性能指标分析,我们发现,在一次作业运行中,大量的时间消耗在网络传输上。
优化:
1. 对数据进行压缩和解压缩,但对CPU消耗比较大,事实上大数据计算通常也是CPU密集型
2. 升级硬件网卡到10G,再看网卡的传输性能曲线,从以前的几十秒缩短了十多秒
1. 对数据进行压缩和解压缩,但对CPU消耗比较大,事实上大数据计算通常也是CPU密集型
2. 升级硬件网卡到10G,再看网卡的传输性能曲线,从以前的几十秒缩短了十多秒
中间件优化
第三层是操作系统的性能优化
红色的是用户程序使用的,表示的是 CPU 的用户态,紫色部分是 CPU 的系统态,红色部分是 User 状态,紫色部分是 sys 状态。紫色部分表示的是当前 CPU 被操作系统占据,执行操作系统的指令。经过进一步的性能分析,发现部分 Linux 版本在缺省状况下打开了 tranparent huge page 这样一个参数,当我们关闭参数的时候,发现处于 sys 状态 CPU 的消耗得到了极大的优化
关闭 tranparent huge page 后,处于 sys 状态消耗的指标,也就是紫色部分消耗的 CPU 指标得到了极大的改善,而整个的系统作业时间也从 200 多秒优化到了 150 多秒。
第四层是虚拟机的性能优化
CMS 垃圾回收线程和用户的线程在很多时候是并发运行的,这也是 CMS 被称为并发垃圾回收器的原因。因为用户线程和垃圾回收线程并发运行,所以在垃圾回收的时候对用户的性能影响相对比较小一点。而在未来,主流的垃圾回收器应该是 G1。
第五层是在虚拟机之下是基础组件的性能优化
tomcat,jetty优化
架构优化
第六层是在基础组件性能优化之下才是软件架构性能优化
缓存
缓存减少了数据库的负载压力,从而可以使数据库提供更多的数据访问
异步
通过分布式消息队列,使系统不同应用之间、不同服务之间异步调用,可以使调用者尽快的返回用户响应,使系统能够得到更好的响应特性
分布式消息队列的异步架构,还有削峰填谷的作用,在访问高峰期,通过异步将用户请求数据写入到消息队列中,在访问低谷的时候还在继续消费处理这些消息,避免对数据库等产生较大的负载访问压力,使系统能够维持在一个较好地响应曲线上。
集群
通过负载均衡的手段,将多种应用服务器构建成一个集群,共同提供服务,以提高系统整个的处理能力,提升系统的响应性能。
代码优化
第七层是在性能优化的最底层才是软件代码的性能优化
第一点是遵循面向对象的设计原则与设计模式编程,避免烂代码。
第二点是并发编程,可以在程序并发运行的时候使用多线程。
第三点是资源的复用。
通过线程池或者数据库连接池对外提供服务
第四点是用异步编程。
在程序内部使用消费者,生产者,以队列数据结构的方式,实现程序内的异步架构,以此来提高系统性能。
第五点是要使用正确的数据结构进行编程。
要熟悉数组、链表、栈、队列、Hash 表、树等常用数据结构,熟悉它们的特性、优缺点以及使用场景,正确地使用它们来管理和访问程序数据
总结
性能优化的前提和基础是性能测试,通过性能测试,了解系统的性能特性才能进行优化,而性能测试主要就是要测试出来系统的性能曲线,通过对性能曲线进行分析,了解系统的瓶颈点和系统资源消耗,再进行性能优化。性能优化的时候需要建立一个整体的思维,要从整体系统的层面去思考优化,而不只是仅仅关注自己的代码,或者是自己设计的架构。
最上层的优化是硬件优化,包括骨干网络、数据中心服务器硬件这样的优化;然后是基础组件的性能优化,包括操作系统、虚拟机、应用中间件这几个方面;这之后才是架构的优化,包括核心的三板斧,缓存、异步和集群;最后才是代码的优化,代码优化的主要手段,有并发、复用、异步以及正确的数据结构,当然最重要的是设计清晰、易维护、易懂、简单、灵活的代码,也就是说最重要的是要遵循面向对象的设计原则和设计模式进行编程。
最上层的优化是硬件优化,包括骨干网络、数据中心服务器硬件这样的优化;然后是基础组件的性能优化,包括操作系统、虚拟机、应用中间件这几个方面;这之后才是架构的优化,包括核心的三板斧,缓存、异步和集群;最后才是代码的优化,代码优化的主要手段,有并发、复用、异步以及正确的数据结构,当然最重要的是设计清晰、易维护、易懂、简单、灵活的代码,也就是说最重要的是要遵循面向对象的设计原则和设计模式进行编程。
系统的安全架构设计
web攻击
XSS攻击
通过构造一个非法的浏览器脚本,让用户跨站点去执行,从而达到攻击的目的。
URL 钓鱼攻击
用户登录了被攻击的服务器,比如微博的服务器,然后他收到了攻击者发送给他的一个含有恶意脚本的 URL,这个 URL 是指向微博服务器的。用户点击恶意 URL 以后,就会把 URL 提交给微博的服务器,同时这段 URL 里面还包含了一段可执行的恶意脚本,这个脚本也会被客户端去执行。在这个恶意脚本里面,会强制用户关注某个特定的微博账号,并发送一条含有恶意脚本的微博,当其他用户浏览点击微博的时候,会再一次执行同样的动作,以此来达到攻击不断扩散的目的。
直接攻击
恶意的攻击者直接攻击被攻击的服务器。
攻击者发送一个含有恶意脚本的请求给被攻击的服务器,比如通过发布微博的方式向微博的服务器发送恶意请求,被攻击的服务器将恶意脚本存储到本地的数据库中,其他正常用户通过被攻击的服务器浏览信息的时候,服务器会读取数据库中含有恶意脚本的数据,并将其展现给正常的用户,在正常用户的浏览器上执行,从而达到攻击的目的。
攻击者发送一个含有恶意脚本的请求给被攻击的服务器,比如通过发布微博的方式向微博的服务器发送恶意请求,被攻击的服务器将恶意脚本存储到本地的数据库中,其他正常用户通过被攻击的服务器浏览信息的时候,服务器会读取数据库中含有恶意脚本的数据,并将其展现给正常的用户,在正常用户的浏览器上执行,从而达到攻击的目的。
SQL注入攻击
恶意的攻击者在提交的请求参数里面,包含有恶意的 SQL 脚本。
CSRF攻击
跨站点请求伪造 CSRF
用户先登录受信任的服务器,然后又访问了被攻击的服务器。被攻击了的服务器返回的响应里面包含着用户访问受信任的服务器的请求,用户在不知情的情况下执行了请求,从而达到了攻击者的目的。
用户先登录受信任的服务器,然后又访问了被攻击的服务器。被攻击了的服务器返回的响应里面包含着用户访问受信任的服务器的请求,用户在不知情的情况下执行了请求,从而达到了攻击者的目的。
web防护
XSS攻击防御
消毒
检查用户提交的请求中是否含有可执行的脚本。可以通过 HTML 转义的方式,比如把“>”转义为“>”这样的转义 HTML 字符,HTML 显示的时候还是正常的”>“,但是这样的脚本无法在浏览器上执行,也就无法达到攻击的目的。
HttpOnly
XSS 攻击的目的是想利用客户端浏览器的权限去执行一些特定的动作,而这种权限通常是需要依赖 Cookie 的,所以可以通过限制脚本访问 Cookie,从而达到防止攻击的目的。也就是在 Cookie 上设置 HttpOnly 的属性,使恶意脚本无法获取 Cookie,避免被攻击脚本攻击。
SQL攻击防御
消毒
通过拦截请求中的数据,对请求数据进行正则表达式匹配,如果请求数据里面包含有某些 SQL 语句,比如“drop table”,那么就对这些语句进行转义和消毒
参数绑定
mybatis通过使用`#{}`占位符、动态SQL、输入参数校验、预编译语句和限制权限等方法,可以有效地防止SQL注入攻击。在开发过程中,需要充分了解和使用这些防御方法,保障系统的安全性。
CSRF攻击防御
表单Token
请求参数是必须要在当前浏览器或者是应用中生成的,比如请求中包含必须要在特定场景下生成的 Token 才能够发送的请求,这样攻击者就无法构造这个 Token,也就无法进行攻击。
Token 利用时间戳、用户设备指纹、页面内容等多方数据进行计算,服务器在收到请求后,对请求包含的 Token 进行校验
验证原理
服务器生成随机数,在表单中添加隐藏域的方式将Token传递给客户端,客户端提交表单时将Token发送回服务器,服务器验证Token的正确性,如果匹配,则允许表单提交,否则拒绝提交。注:也可以加入页面字段再次生成token,比如页面时间等
验证码
要求用户输入图片验证码或者手机验证码,才能够完成
加密
单向散列加密
对一串明文信息进行单向散列加密以后,得到的密文信息是不可以解密的
场景
用户密码加密
将用户密码的明文直接存储到数据库中是比较危险的,如果数据库被内部员工泄露,或者是被黑客拖库以后,那么用户的密码就会被暴露出去。对数据库的密码采用单向散列加密的方式进行保护的。
操作过程
对称加密
使用一个加密算法和一个密钥,对一段明文进行加密以后得到密文,然后使用相同的密钥和对应的解密算法,对密文进行解密,就可以计算得到明文
场景
信用卡在库中要加密存储
在数据库中存储密文,在使用的时候又必须要对密码进行解密,还原得到明文,才能够正常使用。
非对称加密
非对称加密是指在加密的时候使用一个加密算法和一个加密密钥进行加密,得到一个密文,在解密的时候,必须要使用解密算法和解密密钥进行解密才能够还原得到明文,加密密钥和解密密钥完全不同
场景
HTTPS
由于所有的用户都要获得加密密钥,才能够对自己的明文进行加密,所以加密密钥通常也被叫作公钥,意思就是公开的密钥,谁都可以获得得到。但是解密密钥只有互联网系统后端服务器才能够拥有,只能由数据中心的服务器使用,所以也叫作私钥。
为了保证公钥本身的安全性和权威性,通常 HTTPS 的公钥和私钥使用权威的 CA 认证中心颁发的密钥证书。
为了保证公钥本身的安全性和权威性,通常 HTTPS 的公钥和私钥使用权威的 CA 认证中心颁发的密钥证书。
可以用于签名
可以实现数字签名。用数字签名的时候是反过来的,自己用私钥进行加密,得到一个密文,但是其他人可以用公钥将密文解开,因为私钥只有自己才拥有,所以等同于签名。
信息过滤垃圾
分类算法
贝叶斯分类算法,贝叶斯分类算法可以解决概率论中的一个典型问题
布隆过滤器
首先它开辟一块巨大的连续存储空间,比如说开辟一个 16G 比特的连续存储空间,也就是 2G 大的一个内存空间,并将这个空间所有比特位都设置为 0。然后对每个邮箱地址使用多种哈希算法,比如使用 8 种哈希算法,分别计算 8 个哈希值,并保证每个哈希值是落在这个 16G 的空间里的,也就是,每个 Hash 值对应 16G 空间里的一个地址下标。然后根据计算出来的哈希值将对应的地址空间里的比特值设为 1,这样一个邮箱地址就可以将 8 个比特位设置为 1。当检查一个邮箱地址是否在黑名单里的时候,只需要将邮箱地址重复使用这 8 个哈希算法,计算出 8 个地址下标,然后检查这 8 个地址下标里面的二进制数是否全是 1,如果全是 1,那么表示它就是在黑名单里头。使用布隆过滤器,记录同样大小的邮箱黑名单,可以比使用哈希表节约更多的内存空间。
大型架构的演进之路
大型互联网系统的特点
高并发和大流量
一分钟有千万用户访问网站,大规模的并发用户访问对系统的处理能力造成冲击,产生巨大的访问流量
高可用
7*24小时不间断提供服务,保证系统高可用,必须要进行特别的系统架构设计
海量的数据存储
用户多,会产生大量数据,需要对这些数据进行重组和管理。还要通过大数据技术对这些数据进行进一步分析,对用户进行更精准的营销和服务
用户分布广泛,网络情况复杂
为全球用户提供服务,各地网络情况不同,使用户得到统一的良好体验,需要对系统架构进行相关的设计
安全环境恶劣
互联网开放,所以很容易受到攻击
需求变化快,发布频繁
互联网产品快速适应市场,发布频率高
系统处理能力提升的两种途径
垂直伸缩
提升单台服务器的处理能力,比如说用更快频率、更多核的 CPU,用更大的内存,用更快的网卡,用更多的磁盘组成一台服务器,使单台服务器的处理能力得到提升
垂直伸缩的局限
从小型机提升到中型机,从中型机提升到大型机,服务器越来越强大,处理能力也越来越强大,当然价格也越来越昂贵,运维越来越复杂
1. 成本越来越贵
2. 有物理极限
3. 操作系统和应用的计算资源管理复杂
1. 成本越来越贵
2. 有物理极限
3. 操作系统和应用的计算资源管理复杂
水平伸缩
使用更多的服务器,将这些服务器构成一个分布式集群。这个集群统一对外提供服务,来提高系统整体的处理能力。
水平伸缩优点和方案
只要架构合理,能够将服务器添加到集群中,你的系统是可以始终正常运行的
1. 成本低
2. 没有极限
3. 应用程序不受硬件制约
4. 在架构上进行设计,让这些服务器成为整体系统中的一个部分,把它们有效地组织起来,统一提升系统的处理能力。
1. 成本低
2. 没有极限
3. 应用程序不受硬件制约
4. 在架构上进行设计,让这些服务器成为整体系统中的一个部分,把它们有效地组织起来,统一提升系统的处理能力。
大型互联网架构演化进程
最早的时候是单机系统,这时候可以满足少量用户的使用;
随着数据量提升,需要进行应用服务器与数据库分离,这时候可以满足万级用户的使用;
再然后需要通过分布式缓存和服务器集群提升系统性能,可以满足十万级的用户;
之后需要进行反向代理,CDN 加速,还需要数据库读写分离,以满足百万用户级的访问;
随着数据量爆发式增长,使用分布式文件系统和分布式数据库系统,以满足千万级用户的访问;
最后使用搜索引擎、NoSQL、消息队列、分布式服务等更复杂的技术方案,以满足亿级用户的访问。
随着数据量提升,需要进行应用服务器与数据库分离,这时候可以满足万级用户的使用;
再然后需要通过分布式缓存和服务器集群提升系统性能,可以满足十万级的用户;
之后需要进行反向代理,CDN 加速,还需要数据库读写分离,以满足百万用户级的访问;
随着数据量爆发式增长,使用分布式文件系统和分布式数据库系统,以满足千万级用户的访问;
最后使用搜索引擎、NoSQL、消息队列、分布式服务等更复杂的技术方案,以满足亿级用户的访问。
单机系统
少量用户访问
用户少,一般用于验证技术及业务模式是否可行。
应用程序、文件系统、数据库都在一台机器上
应用程序、文件系统、数据库都在一台机器上
数据库与应用分离
可达万级别访问
用户多起来,单机承受不起压力,进行第一次升级,将应用和数据库分离,可达万级别
使用缓存改善性能、应用服务集群化
十万级用户访问
负载均衡调度服务器
应用程序集群化(本地缓存)
数据库主从
文件服务器
分布式缓存
应用程序集群化(本地缓存)
数据库主从
文件服务器
分布式缓存
反向代理和CDN加速
百万级用户访问
CDN服务器(缓存)
反向代理服务器(缓存)
负载均衡调度服务器
反向代理服务器(缓存)
负载均衡调度服务器
1. CDN
指距离用户最近的一个服务器,当访问一个互联网应用的时候,我们的访问请求并不是直接到达互联网站的数据中心的,而是通过运营服务商进行数据转发的。
CDN如果没有我们要的数据,再通过 CDN 进一步访问网站的数据中心,得到数据后再缓存到 CDN 供其他用户访问或下一次访问,所以 CDN 的本质还是一个缓存。
2. 反向代理
通过反向代理的方式代理整个网站的请求服务,先在反向代理服务器中查找是否有用户请求的数据,如果有,就从反向代理服务器直接返回;如果没有,再去请求应用服务器。通过这样的 CDN 和反向代理两级缓存,可以返回绝大部分用户请求的网络数据
指距离用户最近的一个服务器,当访问一个互联网应用的时候,我们的访问请求并不是直接到达互联网站的数据中心的,而是通过运营服务商进行数据转发的。
CDN如果没有我们要的数据,再通过 CDN 进一步访问网站的数据中心,得到数据后再缓存到 CDN 供其他用户访问或下一次访问,所以 CDN 的本质还是一个缓存。
2. 反向代理
通过反向代理的方式代理整个网站的请求服务,先在反向代理服务器中查找是否有用户请求的数据,如果有,就从反向代理服务器直接返回;如果没有,再去请求应用服务器。通过这样的 CDN 和反向代理两级缓存,可以返回绝大部分用户请求的网络数据
应用程序集群化(本地缓存)
数据库主从
文件服务器
分布式缓存
数据库主从
文件服务器
分布式缓存
分布式文件系统和分布式数据库系统
千万级用户访问
分布式文件系统
通过一组服务器集群统一对外提供文件服务。像淘宝的商品图片服务以及 Facebook 这样的相册服务,每天都有大量的用户上传大量的图片
分库分表
消息队列与分布式服务
亿级用户访问
实现强大的计算处理能力
使用的技术手段有分布式消息队列服务、搜索引擎和 NoSQL,以及通过分布式服务,将可复用的业务分离开来,部署在不同的服务器集群上。
消息队列:不同服务、不同应用之间,可以用消息列表解耦,通过消息进行连接,而不是服务调用,使它们之间关系变得低耦合,使系统的处理能力和扩容能力变得更加的强大
消息队列:不同服务、不同应用之间,可以用消息列表解耦,通过消息进行连接,而不是服务调用,使它们之间关系变得低耦合,使系统的处理能力和扩容能力变得更加的强大
子主题
子主题
子主题
总结部分
使用分布式的缓存,提高系统的访问特性,减少数据存储的压力;
使用负载均衡,提供更多的应用服务器提高系统计算处理能力;
使用分布式存储,提供更多的服务器,分摊数据的读写压力;
使用微服务与异步架构,使系统变得更加低耦合,使应用业务变得更加可复用,提升业务处理能力,从而支撑起一个大型网站系统架构。
使用负载均衡,提供更多的应用服务器提高系统计算处理能力;
使用分布式存储,提供更多的服务器,分摊数据的读写压力;
使用微服务与异步架构,使系统变得更加低耦合,使应用业务变得更加可复用,提升业务处理能力,从而支撑起一个大型网站系统架构。
架构核心技术之分布式缓存
几个关键指标:缓存键集合大小、缓存空间大小、缓存的使用寿命。
三个指标决定了缓存的有效性、缓存的使用效率、缓存实现的效果。
缓存的类型:有代理缓存、反向代理缓存、CDN缓存和对象缓存
三个指标决定了缓存的有效性、缓存的使用效率、缓存实现的效果。
缓存的类型:有代理缓存、反向代理缓存、CDN缓存和对象缓存
不适合使用缓存的有:数据频繁修改、数据没有热点、数据不一致、缓存雪崩
缓存的特点
技术简单、
性能提升显著、
应用场景多
性能提升显著、
应用场景多
例:
1. CPU就有缓存,预加载一部分指令和数据到cache中。
2. 操作系统文件缓存,加快访问磁盘文件数据的速度。
3. 数据库的查询缓存,如索引的结构B+树进行缓存,对一些热点数据也要进行缓存。
4. 外部系统比较常用的有DNS客户端缓存、HTTP浏览器缓存、HTTP代理和反向代理缓存、CDN缓存、各种类型的对象缓存(Redis)
1. CPU就有缓存,预加载一部分指令和数据到cache中。
2. 操作系统文件缓存,加快访问磁盘文件数据的速度。
3. 数据库的查询缓存,如索引的结构B+树进行缓存,对一些热点数据也要进行缓存。
4. 外部系统比较常用的有DNS客户端缓存、HTTP浏览器缓存、HTTP代理和反向代理缓存、CDN缓存、各种类型的对象缓存(Redis)
缓存提高性能的优势
三方面优势
1. 缓存的数据来自于内存,访问速度更快
2. 缓存中存储的数据形态通常是最终的结果形态,减少资源消耗
如,缓存一个网页、一个对象、一般都是我们计算过的结果,降低CPU计算消耗
3. 缓存可以降低数据库磁盘或网络的负载压力
缓存数据存储(Hash表)
如何快速获取一个缓存数据
缓存使用的数据结构主要是哈希表,最终的存储形式是一个顺序表,也就是一个数组结构。
通过先计算key的哈希值,找到hash表索引的位置,将key,value存到这个下标数组中。
通过先计算key的哈希值,找到hash表索引的位置,将key,value存到这个下标数组中。
缓存的关键指标---命中率
一次写入,多次读取响应业务,判断指标就叫作缓存的命中率。
影响缓存命中率的主要因素有三个:缓存键集合大小、内存空间大小、缓存的寿命
影响缓存命中率的主要因素有三个:缓存键集合大小、内存空间大小、缓存的寿命
缓存键集合大小
从统计数字上看,唯一键越多,重用的机会越小。比如IP地址缓存天气,需要40亿个键。但如果用国家缓存天气数据,只需几百个。所有尽可能减少缓存键的数量
缓存内存空间大小
物理上缓存空间越大,缓存的对象越多,缓存的命中率也越高
缓存对象生存时间
缓存的时间越长,被重用的可能性就越高。
失效时间有两种:超时失效,清除失效
失效时间有两种:超时失效,清除失效
内存空间清除主要使用的算法LRU,就是最近最久未用算法,这个算法使用链表结构实现的
缓存的主要类型
代理缓存(代理用户上网的)
代理缓存是在应用程序一端的代理,缓存在客户端一端的,代理客户端访问互联网。它的主要作用是互联网访问代理。代理了所有客户端HTTP请求,所以它可以进行页面缓存。
一般情况不作为我们系统架构中的一部分,我们能够管理的是反向代理缓存。
一般情况不作为我们系统架构中的一部分,我们能够管理的是反向代理缓存。
反向代理缓存(代理数据中心输出的)
通过互联网连到数据中心,连接通常是一个反向代理服务器,在本地的反向代理缓存中查找用户请求的数据
反向代理缓存可以多层反向代理缓存,在处理前端通常是一个前端服务器,后面有WEB服务器,之后有应用服务器,再后还有其他的各类服务器。可以对每一层服务器都进行反向代理缓存。
内容分发网络CDN缓存
网络服务商的缓存服务,通过网络服务商提供的网络链接才能连接到数据中心,从CDN中查找静态资源(js,css,图片)数据,不存在则向数据中心请求并缓存到CDN服务器上,再返回客户端
通读缓存
代理缓存、反向代理缓存、CDN缓存都是通读缓存
通读缓存有需要访问的数据时,直接返回,没有,则向真正的数据提供者发出请求。
旁路缓存
前面提到的Key,value这样的对象缓存就是旁路缓存。一般情况是客户端先访问旁路缓存,如果没有,则客户端自己去访问真正的数据提供者,获取数据,再放到旁路缓存中
各种介质数据访问的延迟
合理使用缓存对象
使用缓存时需要注意合理的使用缓存对象
注意频繁修改的数据
一般情况,数据的读写比例至少在2:1以上,缓存才有意义
注意没有热点的访问数据
日常使用的数据通常都是有热点的,实现一次写入多次读取,缓存才有意义
注意数据不一致和脏读
1. 容忍失效时间:业务可以支持缓存中的数据和数据库中的数据延迟一段时间不一致。
2. 强一致:当数据更新时,立即清除缓存中的数据,下次访问这个数据时,重新从数据库中加载并更新缓存
注意缓存雪崩
缓存崩了,访问压力到了数据库上,数据库不能承受访问压力,也会崩。
分布式对象缓存
对象缓存以一个分布式集群的方式对外提供服务,多个应用系统使用同一个分布式对象缓存提供的缓存服务
一致性哈希算法
一致性哈希和余数哈希不同,一致性哈希首先是构建一个一致性哈希环的结构。一致性哈希环的大小是 0~2 的 32 次方减 1,实际上就是我们计算机中无符号整型值的取值范围,这个取值范围的 0 和最后一个值 2 的 32 次方减 1 首尾相连,就构成了一个一致性哈希环
使用虚拟节点。也就是说我们这一个服务器节点放入到一致性哈希环上的时候,并不是把真实的服务器的哈希值放到环上,而是将一个服务器虚拟成若干个虚拟节点,把这些虚拟节点的 hash 值放到环上去。在实践中通常是把一个服务器节点虚拟成 200 个虚拟节点,然后把 200 个虚拟节点放到环上。key 依然是顺时针的查找距离它最近的虚拟节点,找到虚拟节点以后,根据映射关系找到真正的物理节点
架构核心技术之微服务
单体系统的困难
编译部署困难、数据库连接耗尽、服务复用困难、新增业务困难。
编译、部署困难
代码分支管理困难
数据库连接耗尽
新增业务困难
发布困难
微服务框架
Dubbo 和 Spring Cloud,微服务的架构策略。
根据模块以及复用的粒度进行拆分,拆分成多个可以独立部署的分布式服务。应用通过远程访问调用的方式,使用这些服务,构成一个系统
SOA架构
在面向服务的体系架构里面,服务的提供者向注册中心注册自己的服务,而服务的使用者向注册中心去发现服务。发现服务以后,根据服务注册中心提供的访问接口和访问路径对服务发起请求,由服务的提供者完成请求返回结果给调用者
微服务架构
单体应用系统架构,里面的各个模块互相调用、耦合,所有的系统和模块打包在一起,最后组成一个庞大的巨无霸系统。
微服务架构,根据服务的粒度和可复用的级别,对服务进行拆分,以独立部署服务的方式,对外提供服务调用。而应用系统也按照用途和场景的不同,依赖这些可复用的服务,进行逻辑组合,构建成自己的业务系统
微服务架构,根据服务的粒度和可复用的级别,对服务进行拆分,以独立部署服务的方式,对外提供服务调用。而应用系统也按照用途和场景的不同,依赖这些可复用的服务,进行逻辑组合,构建成自己的业务系统
接口调用考虑
1.服务发现与注册:
使用如Eureka, Consul, Zookeeper等服务发现与注册中心,使得微服务能够自动发现其他服务的地址。
2.负载均衡:
在服务消费者端使用负载均衡策略(如Ribbon, Feign)来分发请求到不同的服务提供者实例上。
3.容错机制:
使用如Hystrix的断路器模式来防止因某个微服务故障导致整个系统的崩溃。
4.通信协议:
通常使用HTTP或gRPC作为通信协议。
5.数据一致性:
调用其他服务可能会影响数据的一致性,需要考虑使用分布式事务或最终一致性策略。
6.安全性:(对于大型系统,可能会使用API网关作为统一的入口点,并在这里进行权限校验、流量控制等操作。)
使用如OAuth2, JWT等机制进行服务之间的安全认证和授权。
7.监控与日志:
对服务调用进行监控和记录日志,以便于追踪和排查问题。
使用如Eureka, Consul, Zookeeper等服务发现与注册中心,使得微服务能够自动发现其他服务的地址。
2.负载均衡:
在服务消费者端使用负载均衡策略(如Ribbon, Feign)来分发请求到不同的服务提供者实例上。
3.容错机制:
使用如Hystrix的断路器模式来防止因某个微服务故障导致整个系统的崩溃。
4.通信协议:
通常使用HTTP或gRPC作为通信协议。
5.数据一致性:
调用其他服务可能会影响数据的一致性,需要考虑使用分布式事务或最终一致性策略。
6.安全性:(对于大型系统,可能会使用API网关作为统一的入口点,并在这里进行权限校验、流量控制等操作。)
使用如OAuth2, JWT等机制进行服务之间的安全认证和授权。
7.监控与日志:
对服务调用进行监控和记录日志,以便于追踪和排查问题。
Dubbo
1. 服务提供者
服务的提供者程序在 Dubbo 的服务容器中启动,服务管理容器向服务注册中心进行注册,声明服务提供者所要提供的接口参数和规范,并且注册自己所在服务器的 IP 地址和端口。
2. 服务消费者
服务的消费者如果想要调用某个服务,只需依赖服务提供者的接口进行编程。而服务接口通过 Dubbo 框架的代理访问机制,调用 Dubbo 的服务框架客户端,服务框架客户端会根据服务接口声明,去注册中心查找对应的服务提供者启动在哪些服务器上,并且将这个服务器列表返回给客户端。客户端根据某种负载均衡策略,选择某一个服务器通过远程通讯模块发送具体的服务调用请求。
3. 服务调用
服务调用请求,通过 Dubbo 底层自己的远程通讯模块,也就是 RPC 调用方式,将请求发送到服务的提供者服务器,服务提供者服务器收到请求以后,将该请求发送给服务提供者程序,完成服务的执行,并将服务执行处理结果通过远程调用通讯模块 RPC 返回给服务消费者客户端,服务消费者客户端将结果返回给服务调用程序,从而完成远程服务的调用,获得服务处理的结果。
服务的提供者程序在 Dubbo 的服务容器中启动,服务管理容器向服务注册中心进行注册,声明服务提供者所要提供的接口参数和规范,并且注册自己所在服务器的 IP 地址和端口。
2. 服务消费者
服务的消费者如果想要调用某个服务,只需依赖服务提供者的接口进行编程。而服务接口通过 Dubbo 框架的代理访问机制,调用 Dubbo 的服务框架客户端,服务框架客户端会根据服务接口声明,去注册中心查找对应的服务提供者启动在哪些服务器上,并且将这个服务器列表返回给客户端。客户端根据某种负载均衡策略,选择某一个服务器通过远程通讯模块发送具体的服务调用请求。
3. 服务调用
服务调用请求,通过 Dubbo 底层自己的远程通讯模块,也就是 RPC 调用方式,将请求发送到服务的提供者服务器,服务提供者服务器收到请求以后,将该请求发送给服务提供者程序,完成服务的执行,并将服务执行处理结果通过远程调用通讯模块 RPC 返回给服务消费者客户端,服务消费者客户端将结果返回给服务调用程序,从而完成远程服务的调用,获得服务处理的结果。
Spring Cloud
Spring cloud 的服务提供者通过 Spring Boot 启动,然后向服务注册中心 Eureka Server 进行注册,而服务的消费者通过一个 Zuul 网关访问 Eureka Server 进行服务的发现,获得自己想要调用的远程服务对应的服务地址。获得地址以后,通过 HTTP 的方式向远程的服务提供者发起调用请求。服务提供者完成服务处理后,将处理结果通过 HTTP 返回。从而实现了远程的微服务调用。
熔断
降级
超时管理
微服务架构策略
1. 业务先行,先理顺业务边界和依赖,技术是手段而不是目的
2. 要有独立的功能模块,然后才有分布式的服务
软件功能模块之间的依赖关系就要清晰、合理、规范、便于维护、便于扩展,便于实现新的功能。
服务之间的依赖关系要清晰、参数要简单、耦合关系要少。设计好这样的模块化结构以后,将这些设计好的模块,拆分成独立的微服务进行部署和调用
服务之间的依赖关系要清晰、参数要简单、耦合关系要少。设计好这样的模块化结构以后,将这些设计好的模块,拆分成独立的微服务进行部署和调用
3. 如果模块本身就是混乱的、耦合严重的、边界不清晰的、关系复杂的,那么,把它们拆分成独立的微服务进行部署,只会使事情变得更加复杂。
4. 要搞清楚实施微服务的目的究竟是什么,是为了业务复用,是为了开发边界清晰,是为了分布式集群提升性能,还是仅仅想要使用微服务?目的一定要清楚
注:
进行微服务架构设计之初,就要先做好业务模块的设计和规划。如果做不好模块的划分和耦合管理。那么,宁可晚一点进行微服务架构重构,也不要仓促上马,以免最后带来巨大的损失。
实施微服务的目的是什么:为了业务复用,为了开发边界清晰,为了分布式集群提升性能。
进行微服务架构设计之初,就要先做好业务模块的设计和规划。如果做不好模块的划分和耦合管理。那么,宁可晚一点进行微服务架构重构,也不要仓促上马,以免最后带来巨大的损失。
实施微服务的目的是什么:为了业务复用,为了开发边界清晰,为了分布式集群提升性能。
要根据需求去考虑具体的价值,再根据价值构建我们的设计原则,根据原则寻找最佳实践,最后根据实践去选择最合适的工具。按这样的方式去选择技术做架构设计才是比较成熟和高效的
微服务模式
事件溯源、查询与命令职责分离 CQRS、断路器、超时。
事件溯源
将用户的请求处理过程,每一次的状态变化都记录到事件日志中,并按照时间序列进行持久化的存储,也就是说,把所有的变更操作都按日志的方式,按时间化序列进行记录。
分布式事务
事件溯源是一种办法。因为事件溯源将所有的数据变更都按日志的方式记录起来,所以如果日志不完整,我们就知道事务不完整,可以对事务进行重组或者补偿操作,从而使数据变得一致。
命令与查询职责隔离(CQRS)
在服务接口层面将查询操作(也就是读操作)和命令操作(也就是写操作)隔离开来,在服务层实现读写分离。
在读操作中:主要使用的优化方式是缓存操作。可以将接口层面的查询操作即读操作,尽量多地通过缓存来返回。
写操作:也就是命令操作,主要的性能优化方式是使用消息队列。可以将数据的更新操作,尽量通过消息队列,通过异步化的方式进行处理,以改善性能。
在读操作中:主要使用的优化方式是缓存操作。可以将接口层面的查询操作即读操作,尽量多地通过缓存来返回。
写操作:也就是命令操作,主要的性能优化方式是使用消息队列。可以将数据的更新操作,尽量通过消息队列,通过异步化的方式进行处理,以改善性能。
断路器
服务不可用,可以使用断路器对故障服务进行隔离,在 Spring Cloud 中可以使用 Hystrix 实现断路器。
超时
要设置上游调用者的超时时间大于下游调用者的超时时间之和,相同的超时设置是没有意义的
高可用系统架构设计
`
子主题
子主题
子主题
系统高可用的挑战
在DNS、CDN、应用服务器、数据库宕机、磁盘损坏、网卡松掉、程序BUG引起的故障,我们如何去应对这些挑战,这就是高可用的挑战
可用性度量
可用性指标
一年大概有 53 分钟不可用。这个 99.99% 就叫做系统的可用性指标
年度可用性指标= 1 −(不可用时间/年度总时间)×100%
年度可用性指标= 1 −(不可用时间/年度总时间)×100%
故障分类
故障分类的计算方式是用故障时间乘以故障权重来计算得到的。而故障的权重通常是在故障产生以后,根据影响程度,由运营方确定的一个故障权重值
故障处理流程和故障时间
流程:发现问题,通知负责人,进行故障排查和处理,上线。
复盘:检讨故障产生原因,避免下次出现类似的故障
复盘:检讨故障产生原因,避免下次出现类似的故障
高可用架构一般策略
负载均衡
通过一个负载均衡服务器,将用户的请求分发给多个应用服务器,将多个应用服务器构建成一个集群,共同对外提供服务。
服务器宕机,要有检测并转发给其他服务器的能力,保证用户的请求是成功的。
服务器宕机,要有检测并转发给其他服务器的能力,保证用户的请求是成功的。
实现方法
HTTP重定向负载均衡
用户完成一次访问需要两次请求数据中心,一次请求负载均衡服务器,一次是请求应用服务器;另一个问题是因为响应要重定向到真正的应用服务器,所以需要把应用服务器的 IP 地址暴露给外部用户,这样可能会导致安全性的问题
DNS负载均衡
通常是用域名进行访问,HTTP 协议则必须知道 IP 地址才能建立通信连接,那么域名是如何转换成 IP 地址的呢?就是通过 DNS 服务器来完成。
当用户从浏览器发起发起 HTTP 请求的时候,他输入域名,首先要到 DNS 域名服务器进行域名解析,解析得到 IP 地址以后,用户才能够根据 IP 地址建立 HTTP 连接,访问真正的数据中心的应用服务器,那么就可以在 DNS 域名解析的时候进行负载均衡,不同的浏览器进行解析的时候,返回不同的 IP 地址,从而实现负载均衡。
当用户从浏览器发起发起 HTTP 请求的时候,他输入域名,首先要到 DNS 域名服务器进行域名解析,解析得到 IP 地址以后,用户才能够根据 IP 地址建立 HTTP 连接,访问真正的数据中心的应用服务器,那么就可以在 DNS 域名解析的时候进行负载均衡,不同的浏览器进行解析的时候,返回不同的 IP 地址,从而实现负载均衡。
一般由两层均载均衡
1. DNS解析一次用负载均衡返回不同的IP
2. 返回的IP是nginx反向代理负载均衡服务器
1. DNS解析一次用负载均衡返回不同的IP
2. 返回的IP是nginx反向代理负载均衡服务器
反向代理负载均衡(nginx)
可以提供请求的缓存功能,还进行负载均衡,将用户的请求分发到不同的服务器上面去。
反向代理是工作在 HTTP 协议层上的一个服务器,所以它代理的也是 HTTP 的请求和响应
反向代理是工作在 HTTP 协议层上的一个服务器,所以它代理的也是 HTTP 的请求和响应
缺点:HTTP 协议相对说来,作为互联网第七层的一个协议,它的协议比较重,效率比较低,所以反向代理负载均衡通常用在小规模的互联网系统上,只有几台或者十几台服务器的规模。
IP层负载均衡(四层负载均衡)
当用户的请求到达负载均衡服务器以后,负载均衡服务器会拿到 TCP/IP 的数据包,对数据包的 IP 地址进行转换,修改 IP 地址,将其修改为 Web 服务器的 IP 地址,然后把数据包重新发送出去
缺点:响应的数据不管是 HTML 还是图片,JS、CSS 这样的资源文件通常都会比较大,因此负载均衡服务器会成为响应数据的流量瓶颈
数据链路层负载均衡(交换机)
修改请求的数据帧中的MAC目的地址,让用户原来是发给负载均衡器的请求的数据帧,被二层交换机根据新的MAC目的地址,转发到服务器集群中,对应的服务器(真实服务器,Real Server)的网卡上,这样真实服务器就获得了一个原本目标并不是发送给它的数据帧。
由于二层负载均衡器在转发请求过程中,只修改了帧的MAC目的地址,不涉及更上层协议(没有修改PayLoad数据),所以在上层看来,所有数据是没有改变过的。
由于二层负载均衡器在转发请求过程中,只修改了帧的MAC目的地址,不涉及更上层协议(没有修改PayLoad数据),所以在上层看来,所有数据是没有改变过的。
优点
正是因为实际处理请求的真实物理服务器IP和数据请求中的目的IP是一致的,所以响应结果就不再需要通过负载均衡服务器进行地址交换,我们可以把响应结果的数据包直接从真实服务器返回给用户的客户端,避免负载均衡器网卡带宽成为瓶颈,所以数据链路层的负载均衡效率是相当高的。
缺点
二层负载均衡器直接改写MAC地址的工作原理,决定了它与真实服务器的通讯必须是二层可达的。通俗地说,就是它们必须位于同一个子网当中,无法跨VLAN。
所以,这个优势(效率高)和劣势(不能跨子网)就共同决定了,数据链路层负载均衡器最适合用来做数据中心的第一级均衡设备,用来连接其他的下级负载均衡器。
所以,这个优势(效率高)和劣势(不能跨子网)就共同决定了,数据链路层负载均衡器最适合用来做数据中心的第一级均衡设备,用来连接其他的下级负载均衡器。
备份与失效转移
数据库复制与失效转移
主主复制、主从复制
消息队列隔离
消息的生产者和消费者通过消息队列进行隔离,那么如果消费者出现故障的时候,生产者可以继续向消息队列发送消息,而不会感知到消费者的故障,等消费者恢复正常以后再去到消息队列中消费消息,所以从用户处理的视角看,系统一直是可用的。
分布式消息队列具有削峰填谷的作用,所以在高并发的时候,消息的生产者可以将消息缓存在分布式消息队列中,消费者可以慢慢地到消息队列中去处理,而不会将瞬时的高并发负载压力直接施加到整个系统上,导致系统崩溃。
分布式消息队列具有削峰填谷的作用,所以在高并发的时候,消息的生产者可以将消息缓存在分布式消息队列中,消费者可以慢慢地到消息队列中去处理,而不会将瞬时的高并发负载压力直接施加到整个系统上,导致系统崩溃。
限流与降级
限流:
是指对进入系统的用户请求进行限流处理,如果访问量超过了系统的最大处理能力,就会丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的
注:最好别超过服务的最大处理能力
是指对进入系统的用户请求进行限流处理,如果访问量超过了系统的最大处理能力,就会丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的
注:最好别超过服务的最大处理能力
降级:
在高并发时,某些功能可以先关闭,将资源留下来给比较重要的功能。
在高并发时,某些功能可以先关闭,将资源留下来给比较重要的功能。
异地多活
数据中心分布在多个不同地点的机房里,这些机房都可以对外提供服务,用户可以连接任何一个机房进行访问
重点
DNS域名解析转发
用户请求如何分发到不同的机房去。这个主要可以在域名解析的时候完成,也就是用户进行域名解析的时候,会根据就近原则或者其它一些策略,完成用户请求的分发。
数据同步:
数据同步:
机房数据同步
某个时刻只有一个主机房才能处理请求数据,避免数据同步冲突
高可用运维
自动化测试
采用自动化测试,通过自动化脚本自动对 APP 或者是服务接口进行测试
自动化监控
系统在线上运行的时候,必须要实时的监控系统的各项指标,包括业务指标和技术指标。业务指标包括用户访问量、订单量、查询量这些主要的业务指标,技术指标包括 CPU、磁盘、内存的使用率等。通过这些指标可以实时监控业务是否正常,系统是否正常。如果指标不正常,通过监控报警的手段,通知相关的人员,还可以在自动化监控的基础上去,触发自动化的运维工具,进行自动化的系统修复。
预发布测试
在线上的服务器集群里面有一台服务器,是专门的预发布服务器,这台服务器不配置在负载均衡服务器,也就是说外部的用户是无法访问到这台服务器的,但是这台服务器跟其它的应用服务器,使用的配置、连接的数据库、连接的第三方服务都是完全一样的,它是一个完全线上的一个服务器,而这个服务器只有内部的工程师才可以访问到。
在系统发布的时候,先发布到这台预发布服务器上,然后工程师通过域名绑定的方式,直接访问这台服务器,进行一些关键的业务操作,看系统是否正常。如果正常,那么就将代码同步到其它的服务器上,这时候外部服务器才能够访问到最新的代码。如果发现问题,那么就可以重新进行修复。这个问题虽然是线上的,但是并不会影响到外部用户的使用。预发布的工作原理如下图。
在系统发布的时候,先发布到这台预发布服务器上,然后工程师通过域名绑定的方式,直接访问这台服务器,进行一些关键的业务操作,看系统是否正常。如果正常,那么就将代码同步到其它的服务器上,这时候外部服务器才能够访问到最新的代码。如果发现问题,那么就可以重新进行修复。这个问题虽然是线上的,但是并不会影响到外部用户的使用。预发布的工作原理如下图。
灰度发布
大型互联网系统,会使用一种灰度发布的手段,也就是说每天都只发布一部分服务器,如果出现问题,那么只需要回滚这一部分服务器就可以。发布以后观察一天,第二天再发布一部分服务器。如果没有故障报告,那么就继续发布,如果有故障报告就进行回滚,减少故障的影响力和影响时间。
架构实战案例分析
初创互联网公司架构演化案例
万级日订单级别架构
应用端主要是移动端的应用,通过负载均衡访问 Web 服务器集群,也就是前端集群。
前端集群是两台 Nginx 服务器组成的,在 Nginx 再进行一次负载均衡,将用户请求分发到一组应用服务器集群。
应用服务器集群按照应用场景分为买家系统、卖家系统、供应链系统以及运营系统四个系统集群,
每个系统集群又包含了若干台服务器,所有这些系统都连接到一台 MySQL 服务器上。
前端集群是两台 Nginx 服务器组成的,在 Nginx 再进行一次负载均衡,将用户请求分发到一组应用服务器集群。
应用服务器集群按照应用场景分为买家系统、卖家系统、供应链系统以及运营系统四个系统集群,
每个系统集群又包含了若干台服务器,所有这些系统都连接到一台 MySQL 服务器上。
十万级日订单级别架构
优化
1. 前端使用CDN服务,用户请求的各种静态资源都通过 CDN 服务返回,而所有的商品图片,再通过一个分布式文件系统进行管理。
2. 应用服务器上又加了一个Redis集群
3. mysql做主从复制分离,一主两从分布式,其它业务可以从从服务器获取数据进行业务处理。
4. 大数据平台,对数据的处理的要求也比较高。除了各种各样的统计分析、竞对分析,还有各市场大区的绩效、具体到每个人的绩效都需要进行统计计算,所以专门搭建了一个大数据平台。
1. 前端使用CDN服务,用户请求的各种静态资源都通过 CDN 服务返回,而所有的商品图片,再通过一个分布式文件系统进行管理。
2. 应用服务器上又加了一个Redis集群
3. mysql做主从复制分离,一主两从分布式,其它业务可以从从服务器获取数据进行业务处理。
4. 大数据平台,对数据的处理的要求也比较高。除了各种各样的统计分析、竞对分析,还有各市场大区的绩效、具体到每个人的绩效都需要进行统计计算,所以专门搭建了一个大数据平台。
百万级日订单级别架构
挑战
一个方面是随着订单的增长,业务也变得越来越复杂,开发新的功能变得越来越困难,系统的基本功能维护也越来越困难。另一个方面是,虽然经过了主从分离以及部署了多种缓存以后,高峰期的数据访问压力也可以承受了,但是数据库的存储空间难以满足要求。
优化
1. 微服务拆分:将可复用的一些业务拆分为独立的微服务,进行分布式部署,供应用系统调用,典型的就是用户服务、商品服务、订单服务、红包服务等。
2. 数据库冷热分离:对数据库在原来的主从分离的基础上又做了一次冷热分离。把一部分订单完成的记录,由定时任务备份到其他历史数据库中(如NoSQL中)。保留近一个月的数据作为热点数据,存储访问压力、数据存储压力大大减轻。
3.
1. 微服务拆分:将可复用的一些业务拆分为独立的微服务,进行分布式部署,供应用系统调用,典型的就是用户服务、商品服务、订单服务、红包服务等。
2. 数据库冷热分离:对数据库在原来的主从分离的基础上又做了一次冷热分离。把一部分订单完成的记录,由定时任务备份到其他历史数据库中(如NoSQL中)。保留近一个月的数据作为热点数据,存储访问压力、数据存储压力大大减轻。
3.
分布式存储系统Doris架构案例
设计目标
进行海量的数据存储,也就是说可以在大规模服务器的集群上进行数据存储,可以进行透明的集群管理。
要求能够线性伸缩,当集群存储资源不足的时候,可以很容易地添加服务器到集群中,对集群进行平滑的扩容。
系统要高可用,要能够自动的容错和故障转移,当集群出现服务器宕机故障的时候,不会影响系统的读写,更不会出现数据丢失的情况。
同时要高性能,要在高并发的情况下,依然保持较低的响应时间。
还要具备灵活的扩展能力,可以很方便地扩展新功能。
要有较低的运维成本。可以在无需运维工程师的支持下进行集群的扩容、监控和故障管理。
要求能够线性伸缩,当集群存储资源不足的时候,可以很容易地添加服务器到集群中,对集群进行平滑的扩容。
系统要高可用,要能够自动的容错和故障转移,当集群出现服务器宕机故障的时候,不会影响系统的读写,更不会出现数据丢失的情况。
同时要高性能,要在高并发的情况下,依然保持较低的响应时间。
还要具备灵活的扩展能力,可以很方便地扩展新功能。
要有较低的运维成本。可以在无需运维工程师的支持下进行集群的扩容、监控和故障管理。
架构图
客户端。Doris 给应用程序提供一个客户端的 SDK 包,客户端可以使用 Doris SDK 进行分布式的数据读写操作,Doris 支持存储 Key Value 这样的 KV 数据结构,跟缓存一样。客户端一方面连接 Doris 集群的控制中心 Administration,从控制中心获得配置信息,主要是获得服务器集群的地址端口、角色等配置信息,另一方面获得路由算法信息。
Administration。可以通过控制台进行集群的故障管理和扩容管理。
Data Server 数据存储。Data Server 也是真正的分布式数据存储的地方,Doris 对数据进行分片存储的。根据集群规模、配置信息和算法进行路由计算,计算每个 KV 应该存储的的 Data Server 服务器。Data Server 服务器也和 Administration 服务器进行通信,报告自己的健康状况。应用程序的 KV Client 与 Administration 之间的通讯,只包括配置或者控制信息的通信,不会进行数据通讯,也就是说真正的数据读写操作,只会在 Client 和 Data Server 之间,不需要通过 Administration 进行数据代理。
Administration。可以通过控制台进行集群的故障管理和扩容管理。
Data Server 数据存储。Data Server 也是真正的分布式数据存储的地方,Doris 对数据进行分片存储的。根据集群规模、配置信息和算法进行路由计算,计算每个 KV 应该存储的的 Data Server 服务器。Data Server 服务器也和 Administration 服务器进行通信,报告自己的健康状况。应用程序的 KV Client 与 Administration 之间的通讯,只包括配置或者控制信息的通信,不会进行数据通讯,也就是说真正的数据读写操作,只会在 Client 和 Data Server 之间,不需要通过 Administration 进行数据代理。
Doris 数据分区架构与分区算法
Doris 创造了一种余数哈希和虚拟节点相结合的哈希算法,也就是在 key 进行路由计算的时候,先针对虚拟节点进行一次余数哈希。这个时候会对一个较大的数进行取模,比如说 10万,对 10万 进行取模,计算得到一个虚拟节点。然后对虚拟节点和物理节点进行一次关系映射,根据虚拟节点与物理节点之间的关系进行查找,寻找到真正要访问的物理节点,再将数据写入到这台物理服务器上。这种分区算法的设计,相比于一致性哈希有更好的负载平衡特性。
总结:
1.先对虚拟节点进行余数哈希,得到虚拟节点
2.然后对虚拟节点和物理节点进行一次关系映射
3.将数据写入到物理服务器上
总结:
1.先对虚拟节点进行余数哈希,得到虚拟节点
2.然后对虚拟节点和物理节点进行一次关系映射
3.将数据写入到物理服务器上
反应式编程框架SpringWebFlux
是一种面向数据流和变化传播的编程范式,其目标是实现高效、可伸缩和响应式的系统。它强调通过触发数据流的变化来实现响应式的系统。在响应式编程中,数据流被视为异步事件序列,通过使用基于事件的操作符来处理和响应这些事件。
为什么需要响应式编程
流由生产者生产,并由一或多个消费者消费的元素序列。这种生产者/消费者模型也称发布/订阅模型。
拉模式
消费者主动从生产者拉取元素。
推模式
生产者将元素推送给消费者
子主题
什么是背压
如果消费者消费数据的速度赶不上生产者生产数据的速度,它就会持续消耗系统的资源。使得消费者可以根据自身当前的处理能力通知生产者来调整生产数据的速度,这就是背压
背压机制可以通知生产者当前处理能力,生产者则会调整生产消息的速度
原理
在响应式编程中,背压是由反应式流规范和实现库来处理的。它使用特定的操作符和策略来处理数据流上的背压情况,以确保数据产生和消费之间的平衡。一些常见的背压策略包括缓冲、丢弃、最新值保留
依赖关系
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>{version}</version>
</dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>{version}</version>
</dependency>
spring-boot-starter-webflux包括spring-web , spring-webflux , spring-boot-starter , spring-boot-starter-reactor-netty等,因此不需要任何其他依赖项。
响应流
在Spring WebFlux中,从任何操作返回的数据都打包到响应流中。 这种方法体现了两种类型,它们是WebFlux应用程序的构建块-Mono和Flux 。
Mono是返回零个项目或单个项目( 0..1 )的流,而Flux是返回零个或多个项目( 0..N )的流。
因此,在期望单个(或没有)结果(例如从数据库中检索唯一用户)时,将使用Mono ,而在期望多个结果或某种类型的集合时,将使用Flux 。
Mono是返回零个项目或单个项目( 0..1 )的流,而Flux是返回零个或多个项目( 0..N )的流。
因此,在期望单个(或没有)结果(例如从数据库中检索唯一用户)时,将使用Mono ,而在期望多个结果或某种类型的集合时,将使用Flux 。
0 条评论
下一页