标签:并且 配置连接 点击 而且 结果 架构 出现 逻辑 关注
这里大家可以关注一下我的专栏 《java进阶集中营》 ,每周都会更新到新的内容,如有遗漏,请在文章评论点出,觉得文章不错的,留下你的赞吧!!!
一、高并发带来的后果
导致站点服务器/DB服务器资源被占满崩溃,数据的存储和更新结果和理想的设计是不一样的,比如:出现重复的数据记录,多次添加了用户积分等。
用户角度:
尼玛,这么卡,老子来参加活动的,刷新了还是这样,垃圾网站,再也不来了。
我的经历:
在做公司产品网站的过程中,经常会有这样的需求,比如什么搞个活动专题,抽奖,签到,搞个积分竞拍等等,如果没有考虑到高并发下的数据处理,那就Game Over了,很容易导致抽奖被多抽走,签到会发现一个用户有多条记录,签到一次获得了获得了多积分,等等,各种超出正常逻辑的现象,这就是做产品网站必须考虑的问题,因为这些都是面向大量用户的,而不是像做ERP管理系统,OA系统那样,只是面向员工。
二、并发下的处理
配置数据库连接池C3P0
配置连接池的原因是因为我们要做一个高并发的秒杀系统,可能一些连接会被锁住,其他的线程就可能会拿不到连接的情况,所以我们要调整一下连接池的属性来更符合我们的场景
//当我们用UPDLOCK来读取记录时可以对取到的记录加上更新锁//从而加上锁的记录在其它的线程中是不能更改的只能等本线程的事务结束后才能更改update commodity with (updlock) set count = count-1 where id=?;
③ 如果要实现这样一个需求:cache里面的数据必须每天9点更新一次,其他时间点缓存每小时更新一次。并且到9点的时候,凡是已经打开页面的用户会自动刷新页面。
这里面包含的用户触发缓存更新的逻辑:用户刷新页面,当缓存存在的时候,会获取到最后一次缓存更新的时间。如果当前时间>9点,并且最后缓存时间在9点之前,则会从数据库中重新获取数据保存到cache中。如果大量用户在9点之前已经打开了页面,而且在9点之后还未关闭页面,那么就会导致在9点的时候会有很多并发请求过来,数据库服务器压力暴增。
要解决这个问题,最好就是只有一个请求去数据库获取,其他都是从缓存中获取数据。此时,我们就可以用锁来解决:从数据读取到缓存那段代码前面加上锁,这样在并发的情况下只会有一个请求是从数据库里获取数据,其他都是从缓存中获取。
但是不是所有的方法都需要加事务,比如读操作。
用户大量刷新→CDN(detail页静态化,静态资源js、css等)→高并发系统
原子计数器:主要是高并发的统计的时候要用到。比如:
increment() 和 decrement() 操作是原子的读-修改-写操作。为了安全实现计数器,必须使用当前值,并为其添加一个值,或写出新值,所有这些均视为一项操作,其他线程不能打断它。
解决方案
①MySQL源码层的修改方案:在update后面加上这样一句话:/+[auto_commit]/,当你执行完这条update的时候它会自动回滚。回滚的条件是:update影响的记录数是1就可以commit,如果为0就会rollback。也就是不给java客户端和MySQL之间网络延迟,然后再由java客户端其控制commit和rollback,而是直接通过语句发过去你就告诉我commit和rollback。这个成本比较高,需要修改MySQL源码
②使用存储过程:存储过程的本质就是让一组sql组成一组事务,然后再MySQL端完成,避免客户端完成事务造成性能的干扰。一般情况下,spring声明事务和手动控制事务都是客户端控制事务。这些事务在行级锁没有那么高的竞争情况下是完全OK的,但是秒杀是一个特殊的应用场景,它会在同一行中产生热点,大家都竞争同一行,这个时候存储过程就能够发挥作用了,他把整个sql执行过程放在MySQL端完成,MySQL执行sql的效率非常高。*简单的逻辑我们可以使用存储过程,太过复杂的就不要依赖了。
③通常我们的操作是:减库存(rowLock)→插入购买明细→commit/rollback(freeLock)。我们可以在这个基础上进行一些简单的优化,调换操作的顺序:插入购买明细→减库存(rowLock)→commit/rollback(freeLock),我这样们的延迟就只会发生在update语句这个点上。
脚本合理控制请求
比如用脚本防止用户重复点击导致多余的请求。
使用具有高并发能力的编程语言去开发
nodejs就是一个具有高并发能力的编程语言,它使用单线程异步时间机制,不会因为数据逻辑处理问题导致服务器资源被占用而导致服务器宕机,我们可以使用NodeJs写web接口。
apache模式,以下简称A模式。一共有三个点餐窗口,三位服务人员,三位厨师(请自行脑补画面,但是别乱想)。顾客在任一窗口点餐[所谓多线程],点完后服务员传达厨师,等待厨师出餐,服务员返给顾客[同步返回响应结果]。顾客本次购物结束。服务员进行下一位顾客的点餐[接收下一个请求]。
nodejs模式,以下简称N模式。一共只有一个点餐窗口一位服务员[单线程],一位厨师[CPU]。顾客在窗口点餐,点完后服务员传达厨师,厨师进行出餐,而服务员不必等待[不必等待当前请求返回结果],直接进行下一位顾客的点餐,然后继续传达下一个顾客的订单给厨师。厨师挨个完成后抛出给出餐窗口[异步返回响应结果],顾客到出餐窗口取餐,本次购物结束。
比如要统计用户通过各种方式(如点击图片/链接)进入到商品详情的行为次数,如果同时有1w个用户同时在线访问页面,一次拉动滚动条屏幕页面展示10件商品,这样就会有10w个请求过来,服务端需要把请求的次数数据入库,这样服务器分分钟给跪了。
要解决这些访问量大的数据统计接口的问题,我们可以通过nodejs写一个数据处理接口,把统计数据先存到redis的list中,然后再使用nodejs写一个脚本,脚本的功能就是从redis里取出数据保存到mysql数据库中。这个脚本会一直运行,当redis没有数据需求要同步到数据库中的时候,sleep,然后再进行数据同步操作。
总结
标签:并且 配置连接 点击 而且 结果 架构 出现 逻辑 关注
原文地址:https://blog.51cto.com/15054045/2563249