文档章节

数据库锁和高并发系统

满小茂
 满小茂
发布于 2017/02/17 16:03
字数 1647
阅读 494
收藏 3

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

   

© 著作权归作者所有

共有 人打赏支持
满小茂
粉丝 75
博文 120
码字总数 134867
作品 0
成都
程序员
私信 提问
mysql中select for update锁的问题

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

无标题
2017/12/05
0
0
阿里P8架构师谈:MySQL行锁、表锁、悲观锁、乐观锁的特点与应用

我们在操作数据库的时候,可能会由于并发问题而引起的数据的不一致性(数据冲突)。如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问...

Java高级技术
09/18
0
0
如此牛逼?双11背后的秘密-支付宝app双11最佳实践

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

丁小晶
2016/04/20
0
0
大数据下高并发的处理详解

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

商者
2016/07/18
33
0
支付宝防并发方案之"一锁二判三更新"

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

jackjoe
2017/09/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

render常用模版 结合iview

表格添加一对按钮 { title: '操作', align: 'center', render: (h, params) => { return h('div', [ h('Button', { props: { ......

Carbenson
23分钟前
1
0
一次生产 CPU 100% 排查优化实践

前言 到了年底果然都不太平,最近又收到了运维报警:表示有些服务器负载非常高,让我们定位问题。 还真是想什么来什么,前些天还故意把某些服务器的负载提高(没错,老板让我写个 BUG!),不...

crossoverJie
30分钟前
8
0
Spring Cloud Alibaba Sentinel 整合 Feign 的设计实现

作者 | Spring Cloud Alibaba 高级开发工程师洛夜 来自公众号阿里巴巴中间件投稿 前段时间 Hystrix 宣布不再维护之后(Hystrix 停止开发。。。Spring Cloud 何去何从?),Feign 作为一个跟 ...

Java技术栈
46分钟前
9
0
虚拟机加密

在超融合的基础设施和虚拟化成为常态的世界里,对加密的要求越来越高,越来越迫切,IT部门需考虑的重大安全问题和方法也浮现了出来。 物理数据中心时代,采取双保险式数据安全方法是相对简单...

linuxCool
50分钟前
2
0
MySQL 主从同步

MySQL主从介绍 MySQL主从又叫做Replication、AB复制。简单讲就是A和B两台机器做主从后,在A上写数据,另外一台B也会跟着写数据,两者数据实时同步的 MySQL主从是基于binlog的,主上须开启bin...

野雪球
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部