高并发是指在同一个时间点,有不少用户同时的访问URL地址,好比:淘宝的双11,双12,就会产生高并发,如贴吧的爆吧,就是恶意的高并发请求,也就是DDOS攻击,再屌丝点的说法就像玩撸啊撸被ADC暴击了同样,那伤害你懂得(若是你看懂了,这个说法说明是正在奔向人生巅峰的屌丝。css
致使站点服务器/DB服务器资源被占满崩溃,数据的存储和更新结果和理想的设计是不同的,好比:出现重复的数据记录,屡次添加了用户积分等。html
尼玛,这么卡,老子来参加活动的,刷新了仍是这样,垃圾网站,不再来了。前端
在作公司产品网站的过程当中,常常会有这样的需求,好比什么搞个活动专题,抽奖,签到,搞个积分竞拍等等,若是没有考虑到高并发下的数据处理,那就Game Over了,很容易致使抽奖被多抽走,签到会发现一个用户有多条记录,签到一次得到了得到了多积分,等等,各类超出正常逻辑的现象,这就是作产品网站必须考虑的问题,由于这些都是面向大量用户的,而不是像作ERP管理系统,OA系统那样,只是面向员工。node
下面我进行实例分析,简单粗暴,动态分析,纯属本人我的经验分享,若有说错,或者有更好的建议或者意见的请留言,你们一块儿成长。mysql
经过表设计,如:记录表添加惟一约束,数据处理逻辑使用事物防止并发下的数据错乱问题nginx
经过服务端锁进程防止包并发下的数据错乱问题web
这里主要讲述的是在并发请求下的数据逻辑处理的接口,如何保证数据的一致性和完整性,这里的并发多是大量用户发起的,也可能攻击者经过并发工具发起的并发请求ajax
如例子:经过表设计防止并发致使数据错乱redis
【签到功能】 一天一个用户只能签到一次,
签到成功后用户获取到一个积分sql
用户表,包含积分字段
高并发意淫分析(属于开发前的猜想):
在高并发的状况下,会致使,一个用户签到记录会有多条,或者用户签到后不止加一积分。
首先根据需求我会添加一张签到记录表,重点来了,这张表须要把用户惟一标识字段(ID,Token)和签到日期字段添加为惟一约束,或者惟一索引,这样就能够防止并发的时候插入重复用户的签到记录。而后再程序代码逻辑里,先执行签到数据的添加(这里能够防止并发,添加成功后再进行积分的添加,这样就能够防止重复的添加积分了。最后我仍是建议全部的数据操做都写在一个sql事务里面, 这样在添加失败,或者编辑用户积分失败的时候能够回滚数据。
如例子2(事务+经过更新锁 防止并发致使数据错乱 或者事物+Update的锁表机制)
【抽奖功能】 抽奖一次消耗一个积分 抽奖中奖后编辑剩余奖品总数 剩余奖品总数为0,或者用户积分为0的时候没法进行抽奖
用户表,包含积分字段 奖品表,包含奖品剩余数量字段
在高并发的状况下,会致使用户参与抽奖的时候积分被扣除,而奖品实际上已经被抽完了
在事物里,经过WITH (UPDLOCK) 锁住商品表,或者Update 表的奖品剩余数量和最后编辑时间字段,来把数据行锁住,而后进行用户积分的消耗,都完成后提交事物,失败就回滚。 这样就能够保证,只有可能存在一个操做在操做这件商品的数量,只有等到这个操做事物提交后,其余的操做这个商品行的事物才会继续执行。
如例子3(经过程序代码防止包并发下的数据错乱问题)
【缓存数据到cache里】, 当缓存不存在的时候,从数据库中获取并保存在cache里,若是存在从cache里获取,天天10点必须更新一次,其余时间点缓存两个小时更新一次 到10点的时候,凡是打开页面的用户会自动刷新页面
这里有个逻辑用户触发缓存的更新,用户刷新页面,当缓存存在的时候,会取到最后一次缓存更新时间,若是当前时间大于十点,而且最后缓存时间是10点前,则会从数据库中从新获取数据保存到cache中。 还有客户端页面会在10点时候用js发起页面的刷新,就是由于有这样的逻辑,致使10点的时候有不少并发请求同时过来,而后就会致使不少的sql查询操做,理想的逻辑是,只有一个请求会去数据库获取,其余都是从缓存中获取数据。(由于这个sql查询很耗服务器性能,因此致使在10点的时候,忽然间数据库服务器压力暴增)
C#经过 (锁)lock,在从数据读取到缓存的那段代码前面加上锁,这样在并发的状况下只会有一个请求是从数据库里获取数据,其余都是从缓存中获取。
这接口是给前端ajax使用,访问量会很大,一页面展现的时候就会有几十件商品的展现,滚动条滚到到页面显示商品的时候就会请求接口进行展现数据的统计,每次翻页又会加载几十件
设想若是同时有1W个用户同时在线访问页面,一个次拉动滚动条屏幕页面展现10件商品,这样就会有10W个请求过来,服务端须要把请求数据入库。在实际线上环境可能还会超过这个请求量,若是不通过进行高并发设计处理,服务器分分钟给跪了。
咱们经过nodejs写了一个数据处理接口,把统计数据先存到redis的list里。(使用nodejs写接口的好处是,nodejs使用单线程异步事件机制,高并发处理能力强,不会由于数据逻辑处理问题致使服务器资源被占用而致使服务器宕机) 而后再使用nodejs写了一个脚本,脚本功能就是从redis里出列数据保存到mysql数据库中。这个脚本会一直运行,当redis没有数据须要同步到数据库中的时候,sleep,让在进行数据同步操做
如下我所知道的:
业务从发展的初期到逐渐成熟,服务器架构也是从相对单一到集群,再到分布式服务。
一个能够支持高并发的服务少不了好的服务器架构,须要有均衡负载,数据库须要主从集群,nosql缓存须要主从集群,静态文件须要上传cdn,这些都是能让业务程序流畅运行的强大后盾。
服务器这块可能是须要运维人员来配合搭建,具体我就很少说了,点到为止。
大体须要用到的服务器架构以下:
高并发相关的业务,须要进行并发的测试,经过大量的数据分析评估出整个架构能够支撑的并发量。
测试高并发可使用第三方服务器或者本身测试服务器,利用测试工具进行并发请求测试,分析测试数据获得能够支撑并发数量的评估,这个能够做为一个预警参考,俗话说知己自彼百战不殆。
第三方服务:
并发测试工具:
日用户流量大,可是比较分散,偶尔会有用户高聚的状况;
场景: 用户签到,用户中心,用户订单,等
服务器架构图:
说明:
场景中的这些业务基本是用户进入APP后会操做到的,除了活动日(618,双11,等),这些业务的用户量都不会高汇集,同时这些业务相关的表都是大数据表,业务可能是查询操做,因此咱们须要减小用户直接命中DB的查询;优先查询缓存,若是缓存不存在,再进行DB查询,将查询结果缓存起来。
更新用户相关缓存须要分布式存储,好比使用用户ID进行hash分组,把用户分布到不一样的缓存中,这样一个缓存集合的总量不会很大,不会影响查询效率。
方案如:
以上例子是一个相对简单的高并发架构,并发量不是很高的状况能够很好的支撑,可是随着业务的壮大,用户并发量增长,咱们的架构也会进行不断的优化和演变,好比对业务进行服务化,每一个服务有本身的并发架构,本身的均衡服务器,分布式数据库,nosql主从集群,如:用户服务、订单服务;
秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求
场景:定时领取红包,等
服务器架构图:
说明:
场景中的定时领取是一个高并发的业务,像秒杀活动用户会在到点的时间涌入,DB瞬间就接受到一记暴击,hold不住就会宕机,而后影响整个业务;
像这种不是只有查询的操做而且会有高并发的插入或者更新数据的业务,前面提到的通用方案就没法支撑,并发的时候都是直接命中DB;
设计这块业务的时候就会使用消息队列的,能够将参与用户的信息添加到消息队列中,而后再写个多线程程序去消耗队列,给队列中的用户发放红包;
方案如:
附加:
经过消息队列能够作不少的服务。
如:定时短信发送服务,使用sset(sorted set),发送时间戳做为排序依据,短信数据队列根据时间升序,而后写个程序定时循环去读取sset队列中的第一条,当前时间是否超过发送时间,若是超过就进行短信发送。
高并发请求链接缓存服务器超出服务器可以接收的请求链接量,部分用户出现创建链接超时没法读取到数据的问题;
所以须要有个方案当高并发时候时候能够减小命中缓存服务器;
这时候就出现了一级缓存的方案,一级缓存就是使用站点服务器缓存去存储数据,注意只存储部分请求量大的数据,而且缓存的数据量要控制,不能过度的使用站点服务器的内存而影响了站点应用程序的正常运行,一级缓存须要设置秒单位的过时时间,具体时间根据业务场景设定,目的是当有高并发请求的时候可让数据的获取命中到一级缓存,而不用链接缓存nosql数据服务器,减小nosql数据服务器的压力
好比APP首屏商品数据接口,这些数据是公共的不会针对用户自定义,并且这些数据不会频繁的更新,像这种接口的请求量比较大就能够加入一级缓存;
服务器架构图:
合理的规范和使用nosql缓存数据库,根据业务拆分缓存数据库的集群,这样基本能够很好支持业务,一级缓存毕竟是使用站点服务器缓存因此仍是要善用。
高并发请求数据不变化的状况下若是能够不请求本身的服务器获取数据那就能够减小服务器的资源压力。
对于更新频繁度不高,而且数据容许短期内的延迟,能够经过数据静态化成JSON,XML,HTML等数据文件上传CDN,在拉取数据的时候优先到CDN拉取,若是没有获取到数据再从缓存,数据库中获取,当管理人员操做后台编辑数据再从新生成静态文件上传同步到CDN,这样在高并发的时候可使数据的获取命中在CDN服务器上。
CDN节点同步有必定的延迟性,因此找一个靠谱的CDN服务器商也很重要