高性能大并发服务器架构

一个典型的服务器结构


主要由三部分组成


网络I/O+服务器高性能编程技术+数据库



一:网络I/O

网络I/O方面,linux下面使用 epoll ,windows上面有IOCP,其他平台还有kqueue,dev/poll等机制。


二:服务器及数据库的负载均衡


1.数据库

数据库可能会有以下几点需要解决:


1.超出数据库连接数

    假设数据库并发连接数10个,应用服务器这边有1000个并发访问请求,将会有990个失败。
    
解决方法: 队列 + 连接池
    即加一个中间层DAL(数据库访问层),DAL和应用服务器即可以部署在同一台服务器,
也可以部署在不同台服务器,它们使用TCP通信。最好使用DAL队列服务+连接池的方式。


2.超出时限

数据库并发连接数10个,数据库1秒之内最多能处理1000个请求,应用服务器这边有10000个并发请求,会出现0~10秒的等待



解决方法: 使用缓存
    数据库上的业务逻辑处理应该简单,主要业务逻辑的处理放在应用服务器上。不过这也很有限的降低

数据库的压力。更好的方法是缓存。但是一旦应用了缓存,就会出现缓存的更新,缓存的同步问题。


1.缓存具有一定的时效timeout,如果缓存失效,有两种方法:
(1)对于查询上的缓存,就需要重新去数据库里面查询,查询到数据后更新缓存,进行缓存同步。
将一些热点数据存至缓存,这种方法实时性比较差。
(2)一旦数据库中数据更新,立即通知前端的缓存更新,实时性比较高,但实现有一定难度。


2.缓存换页
内存不够,将不活跃的数据换出缓存。可以使用FIFO,LRU(least recently used)即最近最少使用、
LFU(least frequently used)最近最不频繁使用。
这些技术nosql中都有这种功能。比如redis,memcached都可以作为分布式缓存。
同样,由于 可伸缩性 ,缓存也可以不跟服务器放在同一台机器上。如果放在同一台机器上,它就只是
一个局部的缓存,只能被该机器访问。如果是部署在独立的机器上,并且使用了分布式缓存机制,它就是全局缓存,
可以被各个服务器访问。


那么如果前端还有大并发请求呢?
我们应该做数据库 读写分离
对于大部分数据库而言,数据库的读操作多于写操作。我们可以对数据库进行负载均衡。
现在主流的数据库都有replication机制。
查询到读库,写到写库,对于写数据需要更新到读库,这就是主从分布replication机制。

那么数据库负载均衡了,现在压力又到应用服务器上了。

二.应用服务器

应用服务器的负载均衡
方案一: 应用服务器被动接受任务方案
增加一个任务服务器来实现,任务服务器可以监视应用服务器的负载,到底是CPU高还是I/O高,还是并发
高,或者是内存换页高。
应用服务器可以暴露一个http接口给任务服务器,任务服务器选取负载最低的服务器分配任务。


方案二: 应用服务器主动请求任务方案
当应用服务器任务执行完毕后,主动去任务服务器请求任务。


那么任务服务器如果故障了怎么办呢?
任务服务器需要有两台,甚至多台!任务服务器应该具有 fail over(故障转移 )机制。
当其中一台任务服务器故障或者失效了,另一台应该可以立刻投入使用,它们两者之间通过心跳来实现,
这就是 服务器的高可用 (HA机制high abalitity)。


但是对于大型的应用来说,数据库的量是非常庞大的。
这时候应该对数据库进行数据分区(分库,分表)
分库,即垂直分区,是指数据库可以按照一定的逻辑,把表分散到不同的数据库。比如一个数据库有用户
相关的表,有业务相关的表,有基础信息相关的表,就可以分成三个库。


但更加常用的是水平分区,将一个数据库水平切割为若干个数据库,每个数据库都有这些表,用户表,业务表,信息表。
这种方式需要改写DAL的代码。

三:高性能编程技术

服务器性能四大杀手:
数据拷贝 :应该尽可能减少数据拷贝,内存拷贝,同样得利用缓存机制解决。
环境切换 :(理性创建线程)线程切换,该不该用多线程,单线程好还是多线程好?
答:单核服务器(状态机编程效率是最高的),单核服务器是不能够并行处理任务的。如果使用多线程,
   会增加线程间的切换开销。如果服务器是多核的,多线程能够充分发挥多核并行的优势,但是多核
   服务器使用多线程,也应该尽可能避免线程之间的环境切换。
内存分配 :使用内存池技术解决
锁竞争 :锁竞争会降低程序性能,应该尽可能通过逻辑来避免锁的使用。

猜你喜欢

转载自blog.csdn.net/u012635648/article/details/79359613