架构-1:高性能架构之读写分离和分表分库
架构-2:高性能架构之NoSQL和缓存
架构-3:高性能架构之单机高性能和负载均衡
架构-4:高可用架构之存储高可用
架构-5:高可用架构之Paxos和Raft
架构-6:高可用架构之一致性哈希算法和数据分片
架构-7.高可用架构之接口级故障
单机的性能瓶颈几乎都是在I/O(I/O包括磁盘I/O和网络I/O),为什么,我们来对比下速度。CPU执行一条指令的时间是0.38ns(主频2.6G的CPU),如果把这个时间看成基本单位1秒,那么从磁盘中读取1MB连续数据需要20ms,换算成0.38ns=1秒,20ms约等于20个月。也就是对于阻塞的I/O(即线程在遇到访问I/O的命令时,会进行等待),大部分CPU时间时耗费在等待I/O上。
于是乎,有了I/O多路复用,其原理是:系统会为每一个I/O事件提供一个标志。而我们只需要一个主线程不停的查询所有的标志,当I/O事件准备就绪的时候,才去创建新的线程去执行非I/O的快速命令,极大的释放了CPU的性能。
select是最基础的I/O多路复用,select保存了一个fd_set的数据结构,实际上是一个long类型的数组,每一个数组元素对应一个文件描述符。所谓文件描述符即是上文所讲的系统提供的标志,通过访问这个标志即可知道对应的I/O的状态。由于这是一个数组,所以是固定长度的,固定长度为1024.所以Select能监视的最大I/O事件是1024个。
#include
#define FD_SETSIZE 1024
#define NFDBITS (8 * sizeof(unsigned long))
#define __FDSET_LONGS (FD_SETSIZE/NFDBITS)
typedef struct {
unsigned long fds_bits[__FDSET_LONGS];//定义的数组
} fd_set;
void FD_SET(int fd, fd_set *fdset) //将fd添加到fdset
void FD_CLR(int fd, fd_set *fdset) //从fdset中删除fd
void FD_ISSET(int fd, fd_set *fdset) //判断fd是否已存在fdset
void FD_ZERO(fd_set *fdset) //初始化fdset内容全为0
select执行过程
select的问题
poll与select差不多,唯一的区别在于poll使用链表实现,而是没有1024的长度限制。
epoll是对select/poll的优化版本,epoll有以下好处
那么是怎么做到的呢?
上文聊的是单机高性能,那么多机高性能就不得不提到负载均衡了。通过负载均衡,可以把流量分流到不同的服务器,以降低每一个服务器的压力。
7.应用层
6.表示层
5.会话层
4.传输层
3.网络层
2.数据链路层
1.物理层(硬件)
LVS
LVS是四层负载,也就是在传输层就进行了请求转发,并不需要跟客户端建立TCP连接,服务器跟客户端时直接建立TCP连接的,因此,性能要比Nginx高。据说能够达到80万每秒。但是仅能基于IP和Port进行数据分流。
F5
Nginx和LVS都是软件负载均衡,而F5则是硬件负载,当然其性能就非常高了,从200万/秒到800万/秒都有。但是价格就非常高了,一台F5十来万到上百万都有。
DNS
DNS是最简单的负载均衡,一般来实现地理级别的均衡,如北京的用户访问北京的机房,而深圳的用户访问深圳的机房。DNS的本质就是解析同一个域名可以返回不同的IP地址。DNS的缺点是,更新缓慢,因此只做比较固定的地理级别的均衡。
组合的原则为,DNS用于地理级别的负载均衡,F5用于每个地区的总负载(如果需要的话),Nginx负责机器级别的负载均衡。