文章说明:本文是在学习一个网络爬虫课程时所做笔记,文章如有不对的地方,欢迎指出,积极讨论。
墨菲定律:
1)任何事情没有看起来那么简单
2)所有的事情都会比你预计的时间长
3)可能出错的事情会出错
4)如果你担心某种情况会发生,那么他一般会发生
应对高并发的基本思路(利用机器换内存):
1、加快单机的速度,例如使用redis,提高数据访问频率;增加CPU的内核数,增大内存;
2、增加服务器的数量,利用集群。
并发(Concurrent):在OS中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但在一个时刻点上只有一个程序在处理机上运行。
集群(cluster):是一组相互独立的、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用是,集群像是一个独立的服务器。集群配置是用于提高可用性和可缩放性。
分布式系统设计
(一)无状态
应用本身无状态,状态全部通过配置文件或者集群的服务器端提供并与之同步。进一步,在分布式集群中,如果数据请求的节点可以做到没有状态,意味着任意节点都可以被请求,结合去中心化,就能有效避免单点的访问瓶颈。(机器之间没有关系,使得整个集群能够快速地进入和退出)
(二)拆分
系统设计初期,不要按功能模块来进行拆分,只需要尽快保证每个开发的单元能够独立运行,即按照多进程模式可以运行。
系统拆分的原则:
1.功能及业务:例如搜索模块、地图模块、用户信息模块
2.子功能拆分:例如搜索模块里,图数据库与文本搜索可以分开
3.读写分离:根据读写的特性再进行拆分
4.代码模块:可以按照web、service及DAO(Data AccessObject,数据访问对象)来划分,有专门负责web请求的,有提供进一步数据服务的模块,以及专门的数据库HA管理模块的。
(三)负载均衡
如果单机不行,需要考虑集群,使用集群就意味着一个负载均衡服务提供在最前端。
负载均衡算法:
1.轮询:以轮询的方式把请求发到上游服务器,配合weight配置实现基于权重的轮询
2.IP hash:根据客户的IP做负载均衡,使得IP均衡到同一个upstreamserver
3.hash key:对客户端的一个key进行hash,建议使用一致性hash实现负载均衡。普通hash算法,当添加或删除服务器的时候,即它的容量发生变化的时候,很多key都会重新分配到不同的服务器,使用一致性hash,使得只有极少数的key会被重新分配服务器。
4.leastconnection:把最新的请求负载均衡到活跃连接最少的服务器,依然可以与权重相结合。
一致性hash:将每个对象映射到圆环边上的一个点,系统再将可用的节点机器映射到圆环的不同位置。查找某个对象对应的机器时,需要用一致性hash计算得到对象对应圆环边上位置,沿着圆环边上查找知道遇到某个节点机器,这台机器即为对象应该保存的位置。当删除一台机器时,这台机器上保存的所有对象都要移动到下一台机器。添加一台机器到圆环边上某个点时,这个点的下一台机器需要将这个节点前对应的对象移动到新机器上。更改对象在节点机器上的分布可以通过调整节点机器的位置来实现。
一致性hash的平衡性:通过增加虚拟节点,使得节点的分布及hash算法能实现平衡。
(四)服务化
当服务器集群设计为主从架构的时候,意味着需要有多个主服务器提供备份和容灾,这样就要考虑使用服务的自动注册和发现,比如使用ZooKeeper。
(五)消息队列
用来解耦一些不需要同步调用的服务或者订阅一些通知以及系统的变化。实现服务解耦、异步处理、流量缓冲等。
(六)databus架构 (由LinkedIn发布)
实现MySQL数据与redis的更新操作
(七)数据异构
把一些联合查询的数据,直接组合成一张结果表,这样在读取的时候能更快速地取回结果。通常这样的表会比较大,因此需要按照主键做分库分表来增加读取的性能,带来的问题:
1.数据同步
2.某一项服务的终止导致整体服务的终止
3.聚合查询
(八)缓存 (做后端的尽量让前端的缓存)
1.客户端缓存:浏览器的cookie、storage,APP的本地数据存储 (处理高并发最大的帮助)
2.网络层:CDN,镜像服务器,P2P技术等
3.服务前端:接入层的缓存,应用层缓存
4.分布式缓存:利用redis数据库实现分布式的缓存系统
5.数据库缓存:当所有结果都没命中的情况下,可以依赖数据库的缓存提高检索排序效率
DOS(Denial of Service,拒绝服务)
(九)并发
(十)隔离 (“熔断”)
1.保护资源,以防被其他资源拖垮
2.把不同的数据资源隔开
当海量请求发送到前端的时候,单机的故障率会极大提高,此时一旦一台服务器出故障停止响应,前端反向代理会把请求发送到集群的其他节点,导致整体负载的进一步提升,使得所有的服务请求都被拖累,使得服务器节点如雪崩一样纷纷过载从而导致服务不够用。
因此需要考虑从以下几个维度对访问进行隔离:
1.资源的隔离:比如js、CSS这类访问量极大的文件放在CDN上
2.热点的隔离:一些高频的请求和低频的请求分开
3.读写分离:分布式系统总必用的一点(保证系统高可用很重要的一点)
读写分离—优势
1.物理服务器的增加,负荷增加
2.主从只负责各自的写和读,极大程度地缓解X锁和S锁争用
3.从库可配置myisam引擎,提升查询性能以及节约系统开销
4.主库向从库发送binlog是异步的,从库恢复数据也是异步的
5.特别适用于读大于写的场景
6.可以在从库启动时增加一些参数来提高其读的性能
binlog:二进制日志,记录数据发生或潜在发生更改的SQL语句,并以二进制的形式存储在磁盘中。MySQL的作用类似于oracle的归档日志,可以查看数据库的变更历史(具体的时间点所有的SQL操作)、数据库增量备份和恢复(增量备份和基于时间点的恢复)、MySQL的复制(主主数据库复制、主从数据库复制)。记录了所有的DDL和DML(除了查询语句),以事件形式记录,还包含语句执行所消耗的时间,MySQL的二进制日志是事务安全型的。
读写分离—主从同步
通过主从服务器同步来实现的,主服务器负责写任务,而多个从服务器构成的集群负责读取任务。主服务器负责从binlog读到变化,随后从服务器得到变化,发起请求到主服务器,获得改动的binlog位置,随后发起同步binlog的请求,将所有写操作同步到自己的服务器。
读写分离—HAProxy (一致性方面的考虑)
将实时性、一致性没有需求的请求直接发往从数据库,而实时性要求高的,通过MySQL Proxy请求或者直接向主DB请求。 (比如在交易系统中,最最重要的是交易的时刻。在大多数情况下,我们是能容忍master和slave不一样的。)
(十一)分库分表
1.取模:按照主键取模后做分库分表
2.分区
(十二)限流
HTTP的请求全部发送到任务队列中,当队列满的时候,直接回服务器超时(timeout);队列的大小按照并发处理能力来设置,使得进入队列的请求却能在一定时间内响应。
(十三)降级
指在服务器并发突然增大的时候,启动限制性措施,降低服务提供的能力从而保护系统性能。降级一般是在系统的接口之间,设置降级开关,在特定的时候启用或停用:平峰和低谷期请求通过代理层直达后端;高峰期通过降级,请求都进入到队列,由worker从队列获取数据来请求。
降级措施还包括针对服务级别的,例如在高峰情况下只读缓存,缓存失效的情况下直接返回失败,使得热点的访问能被响应,而非热点数据请求被拒绝;微博打开个人主页的时候,还会出现热点推荐、广告等,如果出现流量保障,可以关闭这些功能的服务接口。