悲观锁(Pessimistic Lock):

适用场景:比如秒杀这种,很多人一起抢着写。
悲观锁:适合写入比较频繁的场景。如果出现大量的读取操作,每次读取的时候都会进行加锁,这样会增加大量的锁的开销,降低了系统的吞吐量。

其实就是select ... for update 的方式。在select数据之前需要先获取到排它锁。
如果获取不到,就需要等待或者抛出异常。(取决于开发者)

经过试验,select ... for update是需要排它锁的。 但是innodb默认隔离级别下直接select是不加锁读,即使之前被上了排它锁,也还是可以读的。
但是不能同时两个select ... for update,因为都需要排它锁。

悲观锁相当于在数据库层面串行化了。显而易见的是随着并发量的增大,事务处理的性能越差。
悲观锁优化方案:
优化悲观锁的方法:核心是各个层面做好排队即可,如:
  • 避免等待时间过长,可以把等待锁的超时时间改短到1秒 innodb_lock_wait_timeout=1(默认是50秒)
  • innodb_thread_concurrency 在InnoDB存储引擎层做“限流”
通过innodb_thread_concurrency参数来控制InnoDB存储引擎层的并发量。将innodb_thread_concurrency设置为16,性能的确会有一定的提升。并发线程数在128的时候,TPS从原有的4300提升为了7200,将近有65%的性能提升。但是在256线程之后,性能依旧堪忧。
  • mysql连接线程池的大小设置为16 在mysql连接池处限制并发数。
性能又获得了进一步的提升。
但是线程池这里有个参数thread_pool_oversubscribe,这个参数其实有点类似云计算中“超售”概念,即MySQL的线程池允许有额外的线程运行。该参数默认是3,之前thread_pool_size设置为16,那么总共允许16*(1+3)=64个线程同时运行。
这个参数的默认值本身没有问题,但是对于秒杀应用来说确是不需要的,因为之前已经讨论过,秒杀应用是串行的。所以将参数thread_pool_oversubscribe设置为1,秒杀还能有进一步的提升。


乐观锁(Optimistic Lock):

乐观锁:适合读取比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。
读数据的时候不加锁,但在更新时需要判断该数据是否被别人修改过
如果数据被其他线程修改,则不进行数据更新。可以通过递增version的方式实现(只要能判断出是否被修改过即可)


总结:两种所各有优缺点,读取频繁使用乐观锁,写入频繁使用悲观锁。
遗留问题:
未经过实践检验


上一篇:mysql秒杀应用
下一篇:简介

成为你想看到的世界变革力量

创建者:jianle
最后更新时间 : 2019年2月9日 0:21

评论