logo  

Java编程实用经验

Java编程实用经验
作者: 陈安廉

摘要:软件开发进阶系列


如何设计高可用高并发系统


2021-09-14 14:13:06

提高系统吞吐量的核心思想是分流,即把服务支撑不了的流量的分散一部分给别的服务处理。而分流又可分为两种方式,一为相同服务集群化进行负载均衡,二为为特定的流量寻找更适合的处理机制或替代品。

高可用系统的核心思想是冗余,当服务发生故障时,冗余的服务能够接替原来的服务。冗余的方式可分两种,冷冗余,一为冗余的服务只有在主服务时效时才提供服务(例如redis主从),二为冗余的服务集群同样提供服务。第二种方式与上面提到的提供吞吐量而进行的集群部署,是同一回事。

具体到项目实践中,高并发系统成了针对项目中具体的并发瓶颈而采取的一系列采取措施,也就是针对某个具体制约因素进行集群化或寻找替代品来实现分流。制约系统吞吐量的因素有多个,而瓶颈就取决于最差的那个。形象的说法就是短板理论,木桶中能装多少水取决于最短的木板有多高。当我们把最短的那个木板加高后,之前倒数第二短的那个木板便成为新的瓶颈。

我们需要从业务的特点出发,分析系统到底需要多高的吞吐量,而制约系统目前能够达到这个吞吐量的瓶颈到底在哪,然后采取对应的措施来进行优化。

可能成为瓶颈因素以及解决方案通常有如下几种:

一、数据库IO瓶颈    

    (一)为数据库寻找替代品,分流部分流量

        1.使用内存缓存Redis替代部分数据库查询

        2.使用搜索引擎Elasticsearch库替代模糊查询       

        3.使用Hbase存储根据主键查询的海量数据    

    (二)数据库的拆分与集群化

        1.读写分离        

        2.分表

        3.分库       

    (三)页面静态化

二、网络连接数瓶颈

    (一)服务器集群

    (二)优化应用程序,提高单机吞吐量

三、缩短响应时长

    (一)异步任务

四、其它

    (一)提高网络带宽

    (二)nginx配置缓存

    (三)CDN加速

    (四)反爬虫及防黑客攻击,对非法访问进行拦截



一、数据库IO瓶颈

(一)为数据库寻找替代品,分流部分流量

1.使用内存缓存Redis替代部分数据库查询

(1)原理

对于可以使用内存缓存,而不需要总是访问数据库的数据,使用缓存替代部分数据库查询。

(2)问题

Redis的高可用部署问题。


2.使用搜索引擎Elasticsearch库替代模糊查询

(1)原理

模糊查询非常慢,应使用合适的分布式数据库来替代。

(2)问题

ES的高可用部署问题。


3.使用Hbase存储根据主键查询的海量数据

(1)原理

根据主键直接查询数据的场景,且能灵活扩容,海量数据对性能影响不大,可选用合适的分布式数据库存储。

(2)问题

Hbase版本选型及客户端选型

(二)数据库的拆分与集群化

1.读写分离

(1)原理

数据库的读写分离提高了数据库的吞吐量,读的高并发与写的并发分离。读服务器不需要加锁,读的并发也不占用写数据库的链接。

数据同步可采用原生的binlog配置,也可采用中间件canal。

数据库的路由可采用shardingjdbc或中间件mycat实现。

(2)问题

需要考虑数据不一致的问题。如果采用同步复制,保证了客户端总能得到最新的数据,但是增加了写事务的时间。

通常可以采用异步复制,虽然增加了一个数据不一致的窗口,但提高了响应时间。


2.分表

(1)原理

单表的数据量达到一定量时将会影响性能,可以考虑对大表进行水平拆分或垂直拆分。

分表可采用客户端实现(shardingjdbc)或中间件(mycat)方式。

(2)问题

分表后导致复杂查询不支持的问题。

mycat的高可用部署问题。


3.分库

(1)原理

当数据库进一步增大时可采用分库,可以根据业务模块进行拆分。

分表可采用客户端实现(shardingjdbc)或中间件(mycat)方式。

(2)问题

分库的数量需要考虑扩容数量问题,要使得主键的哈希能够灵活扩展。

分布式事务的问题,可基于seata实现,常用TA、TCC、SAGA等模式。


(三)页面静态化

(1)原理

页面静态化减少数据库访问。

例如对每一个商品详情生成对应的静态页面。

(2)问题

TODO


二、网络连接数瓶颈

(一)服务器集群

1.原理

部署多个服务进行流量分流,负载均衡。

nginx进行集群的负载均衡。

2.问题

nginx的高可用部署问题。通常采用nginx作为流量分发,然而nginx也可能宕机,所以也需要做集群部署,可以用LVS和keepalived工具来实现nginx的集群部署。

分布式session问题,可以用Redis实现。

分布式锁问题(例如避免超卖现象),可用Redis实现(需要考虑缓存续期问题)。


(二)优化应用程序,提高单机吞吐量

1.原理

tomcat采用阻塞式网络IO,连接数有限,所以可以优化连接数上限,提高单机吞吐量。

例如采用netty做服务器,或者采用servlet3的异步处理替代阻塞处理

2.问题

NIO的使用注意对外内存泄漏的问题。


三、缩短响应时长

(一)异步任务

1.原理

对于一些任务可以采用异步处理的,可采用异步处理,这样响应就可以快速返回而无需等待这些任务的执行完成。

根据实际情况,采用异步线程或mq进行异步处理。

2.问题

mq消息丢失与重复消费问题。

mq高可用部署问题。


四、其它


(一)提高网络带宽

网络带宽成为瓶颈时需要提高网络带宽

(二)nginx配置缓存

项目的页面需要加载很多数据,也不是经常变化的,不涉及个性化定制,为每次请求去动态生成数据,性能比不上根据请求路由和参数缓存一下结果,使用 Nginx 缓存将大幅度提升请求速度。

(三)CDN加速

CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。

CDN就是一个中转站,在给网站主提供一定的方便,用户也可以享受到一定的方便,在提高打开网站和访问速度上面都有大大的提升。

(四)反爬虫及防黑客攻击,对非法访问进行拦截

爬虫以及DOS攻击等会产生大量非法的访问,挤占正常访问。



后记

有些人容易把高并发问题与与微服务架构混淆,实际上这是两个问题,上面那些提高系统吞吐量的措施并不需要进行服务拆分。服务拆分是基于另外的理由:早期的单体架构带来的问题 。

然而,集群部署与服务拆分都会带来一些分布式问题,例如分布式锁、分布式事务。这是共同面临的问题。