AI智能
改变未来

高性能架构模式

读写分离:读写分离的基本原理是将数据库读写操作分散到不同的节点上,

读写分离的基本实现是:

数据库服务器搭建主从集群,一主一从、一主多从都可以。

数据库主机负责读写操作,从机只负责读操作。

数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。

业务服务器将写操作发给数据库主机,将读操作发给数据库从机。

设计复杂度:主从复制延迟和分配机制

复制延迟:1. 写操作后的读操作指定发给数据库主服务器2. 读从机失败后再读一次主机3. 关键业务读写操作全部指向主机,非关键业务采用读写分离

分配机制:将读写操作区分开来,然后访问不同的数据库服务器,一般有两种方式:程序代码封装和中间件封装。

程序代码封装指在代码中抽象一个数据访问层(所以有的文章也称这种方式为“中间层封装”),实现读写操作分离和数据库服务器连接的管理;特点:

实现简单,而且可以根据业务做较多定制化的功能。每个编程语言都需要自己实现一次,无法通用,如果一个业务包含多个编程语言写的多个子系统,则重复开发的工作量比较大。故障情况下,如果主从发生切换,则可能需要所有系统都修改配置并重启。

中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。中间件对业务服务器提供 SQL 兼容的协议,业务服务器无须自己进行读写分离。对于业务服务器来说,访问中间件和访问数据库没有区别,事实上在业务服务器看来,中间件就是一个数据库服务器。

数据库中间件的方式具备的特点是:能够支持多种编程语言,因为数据库中间件对业务服务器提供的是标准 SQL 接口。数据库中间件要支持完整的 SQL 语法和数据库服务器的协议(例如,MySQL 客户端和服务器的连接协议),实现比较复杂,细节特别多,很容易出现 bug,需要较长的时间才能稳定。数据库中间件自己不执行真正的读写操作,但所有的数据库操作请求都要经过中间件,中间件的性能要求也很高。数据库主从切换对业务服务器无感知,数据库中间件可以探测数据库服务器的主从状态。例如,向某个测试表写入一条数据,成功的就是主机,失败的就是从机

分库分表

业务分库指的是按照业务模块将数据分散到不同的数据库服务器,带来的问题:1.join 操作问题2. 事务问题3. 成本问题

单表数据拆分有两种方式:垂直分表和水平分表。垂直分表引入的复杂性主要体现在表操作的数量要增加

水平分表复杂性表现在:某条数据具体属于哪个切分后的子表,需要增加路由算法进行计算:范围路由;Hash 路由:选取某个列(或者某几个列组合也可以)的值进行 Hash 运算,然后根据 Hash 结果分散到不同的数据库表中。同样以用户 ID 为例,假如我们一开始就规划了 10 个数据库表,路由算法可以简单地用 user_id % 10 的值来表示数据所属的数据库表编号,ID 为 985 的用户放到编号为 5 的子表中,ID 为 10086 的用户放到编号为 6 的字表中;配置路由:配置路由就是路由表,用一张独立的表来记录路由信息。同样以用户 ID 为例,我们新增一张 user_router 表,这个表包含 user_id 和 table_id 两列,根据 user_id 就可以查询对应的 table_id。配置路由设计简单,使用起来非常灵活,尤其是在扩充表的时候,只需要迁移指定的数据,然后修改路由表就可以了。配置路由的缺点就是必须多查询一次,会影响整体性能;而且路由表本身如果太大(例如,几亿条数据),性能同样可能成为瓶颈,如果我们再次将路由表分库分表,则又面临一个死循环式的路由算法选择问题

join 操作:需要在业务代码或者数据库中间件中进行多次 join 查询,然后将结果合并;

count() 操作:count() 相加;记录数表:

order by 操作:只能由业务代码或者数据库中间件分别查询每个子表中的数据,然后汇总进行排序

高性能NoSQL

关系数据库存在如下缺点:

1.存储的是行记录,无法存储数据结构2. schema 扩展很不方便3.在大数据场景下 I/O 较高4.全文搜索功能比较弱

常见的 NoSQL 方案分为 4 类。

K-V 存储:解决关系数据库无法存储数据结构的问题,以 Redis 为代表。

文档数据库:解决关系数据库强 schema 约束的问题,以 MongoDB 为代表。

列式数据库:解决关系数据库大数据场景下的 I/O 问题,以 HBase 为代表。

全文搜索引擎:解决关系数据库的全文搜索性能问题,以 Elasticsearch 为代表。

高性能缓存架构

缓存存在的问题:

缓存穿透是指缓存没有发挥作用,业务系统虽然去缓存查询数据,但缓存中没有数据,业务系统需要再次去存储系统查询数据。通常情况下有两种情况:1. 存储数据不存在2. 缓存数据生成耗费大量时间或者资源,第二种情况是存储系统中存在数据,但生成缓存数据需要耗费较长时间或者耗费大量资源。如果刚好在业务访问的时候缓存失效了,那么也会出现缓存没有发挥作用,访问压力全部集中在存储系统上的情况。

缓存雪崩是指当缓存失效(过期)后引起系统性能急剧下降的情况;

缓存雪崩的常见解决方法有两种:更新锁机制和后台更新机制。

对缓存更新操作进行加锁保护,保证只有一个线程能够进行缓存更新,未能获取更新锁的线程要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

由后台线程来更新缓存,而不是由业务线程来更新缓存,缓存本身的有效期设置为永久,后台线程定时更新缓存。

缓存热点:缓存热点的解决方案就是复制多份缓存副本,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台缓存服务器压力

单服务器高性能模式:PPC与TPC

性能架构设计主要集中在两方面:尽量提升单服务器的性能,将单服务器的性能发挥到极致。如果单服务器无法支撑性能,设计服务器集群方案。

单服务器高性能的关键之一就是服务器采取的并发模型,并发模型有如下两个关键设计点:服务器如何管理连接。服务器如何处理请求。以上两个设计点最终都和操作系统的 I/O 模型及进程模型相关。I/O 模型:阻塞、非阻塞、同步、异步。进程模型:单进程、多进程、多线程。

PPC 是 Process Per Connection 的缩写,其含义是指每次有新的连接就新建一个进程去专门处理这个连接的请求,单个服务器也就处理几百个连接

TPC 是 Thread Per Connection 的缩写,其含义是指每次有新的连接就新建一个线程去专门处理这个连接的请求,但服务器每秒可处理上万的连接

单服务器高性能模式:Reactor与Proactor

Reactor 是非阻塞同步网络模型,因为真正的 read 和 send 操作都需要用户进程同步操作

I/O 多路复用技术归纳起来有两个关键实现点:

当多条连接共用一个阻塞对象后,进程只需要在一个阻塞对象上等待,而无须再轮询所有连接,常见的实现方式有 select、epoll、kqueue 等。

当某条连接有新的数据可以处理时,操作系统会通知进程,进程从阻塞状态返回,开始进行业务处理。

Reactor,是“事件反应”的意思,可以通俗地理解为“来了一个事件我就有相应的反应”,这里的“我”就是 Reactor,具体的反应就是我们写的代码,Reactor 会根据事件类型来调用相应的代码进行处理。Reactor 模式也叫 Dispatcher 模式(在很多开源的系统里面会看到这个名称的类,其实就是实现 Reactor 模式的),更加贴近模式本身的含义,即 I/O 多路复用统一监听事件,收到事件后分配(Dispatch)给某个进程。

Reactor 模式的核心组成部分包括 Reactor 和处理资源池(进程池或线程池),其中 Reactor 负责监听和分配事件,处理资源池负责处理事件。初看 Reactor 的实现是比较简单的,但实际上结合不同的业务场景,

Reactor 模式的具体实现方案灵活多变,主要体现在:

Reactor 的数量可以变化:可以是一个 Reactor,也可以是多个 Reactor。

资源池的数量可以变化:以进程为例,可以是单个进程,也可以是多个进程(线程类似)。

将上面两个因素排列组合一下,理论上可以有 4 种选择,但由于“多 Reactor 单进程”实现方案相比“单 Reactor 单进程”方案,既复杂又没有性能优势,因此“多 Reactor 单进程”方案仅仅是一个理论上的方案,实际没有应用。

最终 Reactor 模式有这三种典型的实现方案:单 Reactor 单进程 / 线程。单 Reactor 多线程。多 Reactor 多进程 / 线程。

Proactor 可以理解为“来了事件我来处理,处理完了我通知你

详细介绍一下 Proactor 方案:

Proactor Initiator 负责创建 Proactor 和 Handler,并将 Proactor 和 Handler 都通过 Asynchronous Operation Processor 注册到内核。

Asynchronous Operation Processor 负责处理注册请求,并完成 I/O 操作。

Asynchronous Operation Processor 完成 I/O 操作后通知 Proactor。

Proactor 根据不同的事件类型回调不同的 Handler 进行业务处理。

Handler 完成业务处理,Handler 也可以注册新的 Handler 到内核进程。

高性能负载均衡:分类及架构

高性能集群的复杂性主要体现在需要增加一个任务分配器,以及为任务选择一个合适的任务分配算法

对于任务分配器,现在更流行的通用叫法是“负载均衡器”。但这个名称有一定的误导性,会让人潜意识里认为任务分配的目的是要保持各个计算单元的负载达到均衡状态。而实际上任务分配并不只是考虑计算单元的负载均衡,不同的任务分配算法目标是不一样的,有的基于负载考虑,有的基于性能(吞吐量、响应时间)考虑,有的基于业务考虑。

负载均衡不只是为了计算单元的负载达到均衡状态。

常见的负载均衡系统包括 3 种:DNS 负载均衡、硬件负载均衡和软件负载均衡。

DNS 负载均衡实现简单、成本低,但也存在粒度太粗、负载均衡算法少等缺点。

其优点有:简单、成本低:负载均衡工作交给 DNS 服务器处理,无须自己开发或者维护负载均衡设备。

就近访问,提升访问速度:DNS 解析时可以根据请求来源 IP,解析成距离用户最近的服务器地址,可以加快访问速度,改善性能。

缺点有:

更新不及时:DNS 缓存的时间比较长,修改 DNS 配置后,由于缓存的原因,还是有很多用户会继续访问修改前的 IP,这样的访问会失败,达不到负载均衡的目的,并且也影响用户正常使用业务。

扩展性差:DNS 负载均衡的控制权在域名商那里,无法根据业务特点针对其做更多的定制化功能和扩展特性。

分配策略比较简单:DNS 负载均衡支持的算法少;不能区分服务器的差异(不能根据系统与服务的状态来判断负载);也无法感知后端服务器的状态。

针对 DNS 负载均衡的一些缺点,对于时延和故障敏感的业务,有一些公司自己实现了 HTTP-DNS 的功能,即使用 HTTP 协议实现一个私有的 DNS 系统。这样的方案和通用的 DNS 优缺点正好相反

硬件负载均衡是通过单独的硬件设备来实现负载均衡功能,这类设备和路由器、交换机类似,可以理解为一个用于负载均衡的基础网络设备。目前业界典型的硬件负载均衡设备有两款:F5 和 A10

硬件负载均衡的优点是:

功能强大:全面支持各层级的负载均衡,支持全面的负载均衡算法,支持全局负载均衡。

性能强大:对比一下,软件负载均衡支持到 10 万级并发已经很厉害了,硬件负载均衡可以支持 100 万以上的并发。

稳定性高:商用硬件负载均衡,经过了良好的严格测试,经过大规模使用,稳定性高。

支持安全防护:硬件均衡设备除具备负载均衡功能外,还具备防火墙、防 DDoS 攻击等安全功能。

硬件负载均衡的缺点是:

价格昂贵:最普通的一台 F5 就是一台“马 6”,好一点的就是“Q7”了。

扩展能力差:硬件设备,可以根据业务进行配置,但无法进行扩展和定制

软件负载均衡通过负载均衡软件来实现负载均衡功能,常见的有 Nginx 和 LVS,其中 Nginx 是软件的 7 层负载均衡,LVS 是 Linux 内核的 4 层负载均衡。4 层和 7 层的区别就在于协议和灵活性,Nginx 支持 HTTP、E-mail 协议;而 LVS 是 4 层负载均衡,和协议无关,几乎所有应用都可以做,例如,聊天、数据库等。

软件和硬件的最主要区别就在于性能,硬件负载均衡性能远远高于软件负载均衡性能。Ngxin 的性能是万级,一般的 Linux 服务器上装一个 Nginx 大概能到 5 万 / 秒;LVS 的性能是十万级,据说可达到 80 万 / 秒;而 F5 性能是百万级,从 200 万 / 秒到 800 万 / 秒都有(数据来源网络/)。当然,软件负载均衡的最大优势是便宜,一台普通的 Linux 服务器批发价大概就是 1 万元左右,相比 F5 的价格,那就是自行车和宝马的区别了。

软件负载均衡的优点:

简单:无论是部署还是维护都比较简单。

便宜:只要买个 Linux 服务器,装上软件即可。

灵活:4 层和 7 层负载均衡可以根据业务进行选择;

也可以根据业务进行比较方便的扩展,例如,可以通过 Nginx 的插件来实现业务的定制化功能。

其实下面的缺点都是和硬件负载均衡相比的,并不是说软件负载均衡没法用。

性能一般:一个 Nginx 大约能支撑 5 万并发。

功能没有硬件负载均衡那么强大。

一般不具备防火墙和防 DDoS 攻击等安全功能。

负载均衡典型架构:

组合的基本原则为:DNS 负载均衡用于实现地理级别的负载均衡;硬件负载均衡用于实现集群级别的负载均衡;软件负载均衡用于实现机器级别的负载均衡。

高性能负载均衡:算法

负载均衡算法数量较多,大体上可以分为下面几类。

任务平分类:负载均衡系统将收到的任务平均分配给服务器进行处理,这里的“平均”可以是绝对数量的平均,也可以是比例或者权重上的平均。

负载均衡类:负载均衡系统根据服务器的负载来进行分配,这里的负载并不一定是通常意义上我们说的“CPU 负载”,而是系统当前的压力,可以用 CPU 负载来衡量,也可以用连接数、I/O 使用率、网卡吞吐量等来衡量系统的压力。

性能最优类:负载均衡系统根据服务器的响应时间来进行任务分配,优先将新任务分配给响应最快的服务器。

Hash 类:负载均衡系统根据任务中的某些关键信息进行 Hash 运算,将相同 Hash 值的请求分配到同一台服务器上。常见的有源地址 Hash、目标地址 Hash、session id hash、用户 ID Hash 等。

轮询:只要服务器在运行,运行状态是不关注的

加权轮询是轮询的一种特殊形式,其主要目的就是为了解决不同服务器处理能力有差异的问题

负载最低优先:根据连接数,http请求数或者cpu性能等自定义算法,来实现

性能最优优先:类算法则是站在客户端的角度来进行分配的,优先将任务分配给处理速度最快的服务器,通过这种方式达到最快响应客户端的目的

Hash 类:负载均衡系统根据任务中的某些关键信息进行 Hash 运算,将相同 Hash 值的请求分配到同一台服务器上,这样做的目的主要是为了满足特定的业务需求;源地址 Hash;ID Hash

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 高性能架构模式