文档章节

数据库锁和高并发系统

满小茂
 满小茂
发布于 2017/02/17 16:03
字数 1647
阅读 415
收藏 3
点赞 0
评论 0

1.QPS      

      Web系统开发中,会有一种常见的高并发系统,对系统吞吐量要求很高,一般的管理系统用户访问量不大对高并发要求并不够,如果对用户访问量很大的系统,如电商,搜索引擎等API接口,要求会特别的高。其中QPS(Quest per seconds)会有一个计算公式:

             QPS(TPS)= 并发数/响应时间(单位秒);  

       并发数: 可以理解为单位时间内请求接口的用户数量。 系统能同时处理的request/(事务数),可以理解为网络能同时打开的通道,最直接的是Linux系统,每个进程能开启的网络通道个数,比如默认可以打开1024个网络文件描述符。

      响应时间:  一般取平均响应时间,是每个http请求从请求开始到结束花销的时间,一般取系统各个接口的平均时间。

      举个例子,我们假设处理一个业务请求平均响应时间为100ms,同时,系统内有20台Web服务器,配置MaxClients为500个(表示服务器的最大连接数目)。那么,我们的Web系统的理论峰值QPS为(理想化的计算方式):20*500/0.1 = 100000 (10万QPS)。

2.高并发系统设计

      现在的web系统基本都是基于关系型数据库的,比如互联网最喜欢的MySql系统,当高并发系统中,最简单的是使用悲观锁的方式,不管是数据库还是代码当中,但是这并不是比较好的解决方式。锁的性能是低效的。

       例子:

      当用户请求涉及数据库值修改时,多个用户同时修改值,可能会造成错误,当使用悲观锁时,每次只允许一个用户修改值,比如商品出货这个操作。

        a.查询商品剩余的数量 : select numbers from goods where good_id=${good_id}

        b.生成订单: insert into orders(user_id,good_id) values('12345',${good_id})

        c.减少商品剩余数量: update goods set numbers=numbers-1 where good_id=${good_id}

       一个商品订单操作可以分为这几步,但是如果在多线程情况下,当商品数量剩余数量为1的时候,多个用户同时下单,同时发现商品用户数量为1,都生成了一条订单,实际上商品只有一个了,造成数据不一致错误。

(1) 队列方案

         将用户的所有请求都放入放入队列中,然后消费者线程从队列中取数据,一个一个的处理,这种方式可以一定程度减少并发度,但是如果用户数量暴增,队列入队数量会远高于出队数量,最后导致系统出错,消费堵塞。

(2) 悲观锁方案

       要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。

     我们可以使用命令设置MySQL为非autocommit模式:        

 set autocommit=0;
// 0.开始事务
 begin;
// 1.查询出商品信息
 select numbers from goods where good_id=${good_id} for update;
// 2.根据商品信息生成订单
 insert into orders(user_id,good_id) values('12345',${good_id})
// 3.修改商品剩余数量减少一个
 update goods set numbers=numbers-1 where good_id=${good_id}
// 4.提交事务
 commit;

       上面的begin/commit为事务的开始和结束,因为在前一步我们关闭了mysql的autocommit,所以需要手动控制事务的提交,在这里就不细表了。

        在事务中,只有SELECT ... FOR UPDATE  同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。

      MySQL select…for update的Row Lock与Table Lock

     使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认Row-Level Lock,所以只有明确地指定主键或者索引,MySQL 才会执行Row lock 只锁住被选取的数据),否则MySQL 将会执行Table Lock 将整个数据表单给锁住。

      但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是对长事务而言,这样的开销往往无法承受。

(3)乐观锁方案

              

      为了减少锁竞争,我们可以采用悲观锁的方式来实现高并发操作,为需要高并发访问的数据表建立一个version字段,然后操作。

a.查询商品剩余的数量 : select numbers,version from goods where good_id=#{good_id};

b.生成订单: insert into orders(user_id,good_id) values('12345',#{good_id})

c.减少商品剩余数量: update goods set numbers=numbers-1 where good_id=#{good_id} and version=#{version}

  (4)CAS高并发系统

       Compare And Swap 为了降低锁竞争带来的低效率,我们在高并发系统中应该尽量减少锁的使用,而使用CAS无锁操作.

     独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁用到的机制就是CAS,Compare and Swap。

        在Java并发包中有这样一个包,java.util.concurrent.atomic,该包是对Java部分数据类型的原子封装,在原有数据类型的基础上,提供了原子性的操作方法,保证了线程安全。下面以AtomicInteger为例,来看一下是如何实现的。

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}
public final int decrementAndGet() {
    for (;;) {
        int current = get();
        int next = current - 1;
        if (compareAndSet(current, next))
            return next;
    }
}

 GCC4.1+版本中支持CAS的原子操作(完整的原子操作可参看 GCC Atomic Builtins

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)

type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)

高并发队列推荐使用Disruptor,CAS无锁队列
另外秒杀抢购业务可以参考这篇博文,写得不错

 https://my.oschina.net/wangjie404/blog/815455

   

© 著作权归作者所有

共有 人打赏支持
满小茂
粉丝 65
博文 108
码字总数 121544
作品 0
成都
程序员
mysql中select for update锁的问题

mysql中select for update锁的问题 无标题2017-12-053 阅读 mysql 在日常关于资金业务的开发过程中,涉及到数据库的操作时我们经常按照一查二锁三写的套路,可能在加锁后还需要查询一些数据,...

无标题 ⋅ 2017/12/05 ⋅ 0

如此牛逼?双11背后的秘密-支付宝app双11最佳实践

近来,FF项目的运营活动越来越多,对于架构设计以及程序研发有了更高的要求,参考国内互联网公司对于营销活动app的设计思路,我们找到了最具有代表性的支付宝双11活动,阐述运营活动类高并发...

丁小晶 ⋅ 2016/04/20 ⋅ 0

大数据下高并发的处理详解

对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了。而并发问题是绝大部分的程序员头疼的问题,但话又说回来了,既然逃避不掉,那我们就要想想应对措...

商者 ⋅ 2016/07/18 ⋅ 0

探索并发编程(七)------分布式环境中并发问题

在分布式环境中,处理并发问题就没办法通过操作系统和JVM的工具来解决,那么在分布式环境中,可以采取一下策略和方式来处理: 避免并发 时间戳 串行化 数据库 行锁 统一触发途径 避免并发 在...

老先生二号 ⋅ 2017/07/30 ⋅ 0

支付宝防并发方案之"一锁二判三更新"

每年支付宝在双11和双12的活动中,都展示了绝佳的技术能力。这个能力不但体现在处理高TPS量的访问,更体现在几乎不会出错,不会出现重复支付的情况,那这个是怎么做到的呢? 诚然,为了实现在...

jackjoe ⋅ 2017/09/16 ⋅ 0

Linux下同步异步机制以及高性能服务器的相关话题

同步线程与异步线程的比较?(同样适合于同步进程和异步进程) 进程和线程的同步是指:程序的执行顺序完全由代码序列决定。 同步线程的特点: 代码逻辑简单,适合高并发量,但是效率低,实时...

LinuxCPlusPlus ⋅ 2016/02/20 ⋅ 0

秒杀技术选型

一、控制库存的技术选型有五个选择 (1)mysql乐观锁 (2)mysql悲观锁 (3)redis的原子操作incr (4)redis的watch(redis乐观锁) (5)redis执行lua脚本 二、测试结果(8核16G,300个线程...

钟主华 ⋅ 2016/06/30 ⋅ 15

mysql5.6压力测试 sysbench工具

面对高并发大流量服务器,根据业务需要往往需要对数据库,操作系统I/O,带宽等等做压力测试.从而来判断什么时候要做负载均衡,增加服务器等来为业务支撑做准备。linux系统可以通过iotop,dst...

落叶刀 ⋅ 2015/09/17 ⋅ 0

小柒2012/spring-boot-seckill

分布式秒杀系统 开发环境 JDK1.7、Maven、Mysql、Eclipse、SpringBoot1.5.10、zookeeper3.4.6、kafka_2.11、redis-2.8.4、curator-2.10.0 友情提示 由于工作原因,项目正在完善中(仅供参考)...

小柒2012 ⋅ 05/19 ⋅ 0

数据库 for update 悲观锁替代方案

账务系统,单个账户资金变动很频繁,现在是行集锁记录for update, 大神们在高并发,这种账务系统修改资金变动,还要插入资金变动明细等一系列操作时候使用悲观锁是否效率受影响? 那么乐观锁...

wad12302 ⋅ 2016/11/22 ⋅ 5

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Thrift RPC实战(二) Thrift 网络服务模型

TServer类层次体系 TSimpleServer/TThreadPoolServer是阻塞服务模型 TNonblockingServer/THsHaServer/TThreadedSelectotServer是非阻塞服务模型(NIO) 1 TServer抽象类的定义 内部静态类Args的...

lemonLove ⋅ 11分钟前 ⋅ 0

vim命令用法

第五章 vim命令 vim和vi几乎是一样的,唯一的区别就是当编辑一个文本时,使用vi不会显示颜色,而使用vim会显示颜色。 vim有三个模式:一般模式,编辑模式,命令模式。 系统最小化安装时没有安...

弓正 ⋅ 12分钟前 ⋅ 0

MyBatis源码解读之配置

1. 目的 本文主要介绍MyBatis配置文件解析,通过源码解读mybatis-config.xml(官方默认命名)、Mapper.xml 与Java对象的映射。 2. MyBatis结构 查看大图 MyBatis结构图,原图实在太模糊了,所以...

无忌 ⋅ 16分钟前 ⋅ 0

Ignite的jdbc与网格的连接方式的查询性能对比

环境: 数据量100万 Ignite2.5 Windows10 8g jdbc方式连接 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; i......

仔仔1993 ⋅ 31分钟前 ⋅ 0

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 46分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 53分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 今天 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 今天 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 今天 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部