文章每周持续更新,各位的「三连」是对我最大的确定。能够微信搜索公众号「 后端技术学堂 」第一时间阅读(通常比博客早更新一到两篇)程序员
号召在家宅着抵抗疫情,拜年也改用微信红包,春节发了不少也抢了不少微信红包,微信支付融入生活,抢红包已是很是日常的事情。redis
抢红包这一简单的动做,每一次都是对红包服务后台的一次请求,在春节期间海量的服务请求下,实际上是一个很典型的高并发编程模型。后台开发程序员都有一个共识:实现一个功能很容易,难的是大量请求下提升服务性能。数据库
在程序员眼里,你们抢的不是红包,是红包后台服务的锁 !这里的锁不是咱们平常生活中的锁,后台服务编程中锁的概念:编程
实现多个进程或线程互斥的访问共享资源的一种机制后端
为便于说明,咱们简化模型,约定抢红包服务是多线程服务,抢红包操做包含如下3个步骤:缓存
假设你发了100块钱红包,1000我的1秒内同时来抢(高并发),若是不加锁是这样的状况:服务器
怎么解决这个问题呢? 就用到咱们上面说的加锁来解决。微信
实现锁的方式有不少,这里列举几种常见的分类数据结构
顾名思义就是悲观的作最坏打算的锁机制,占有锁期间独占资源。多线程
悲观锁把抢红包这三个步骤打包成一个总体作成互斥操做,“在我抢了没更新数据以前你别来查余额,查到也不许确”。也能够类比数据库的事务来理解。
事务必须具有如下四个属性,简称ACID 属性: 原子性(Atomicity):事务是一个完整的操做。事务的各步操做是不可分的(原子的);要么都执 行,要么都不执行 一致性(Consistency):当事务完成时,数据必须处于一致状态 隔离性(Isolation):对数据进行修改的全部并发事务是彼此隔离的,这代表事务必须是独立的,它不该以任何方式依赖于或影响其余事务 永久性(Durability):事务完成后,它对数据库的修改被永久保持,事务日志可以保持事务的永久性
它悲观的认为你每次去抢红包必然有其余人也同时在抢,因此你这条线程在抢的时候要独占资源,其余线程须要阻塞挂起等待你抢完才能进来抢,挂起的线程就干不了其余事了。
鲁迅先生说过,浪费CPU资源就是浪费生命!
而一旦你抢完红包释放了锁,其余在等待中的线程又要抢占资源、抢到了还要恢复线程上下文。
CPU不断的切换线程上下文很是浪费服务器资源,严重的会致使不能及时处理后续抢红包请求,须要想办法提升效率,因而有了乐观锁
乐观锁是对悲观锁的改进,乐观的认为加锁的时候没有竞争,乐观锁不阻塞线程。
一种实现乐观锁的方法是数据库内红包余额增长版本号,初始版本号是0,每次抢完红包版本号加1后再去更新余额,**只有更新的版本号大于数据库内的版本号才认为是合法的,予以更新;不然不予更新,线程不阻塞能够稍后重试,**避免频繁切换线程上下文。
乐观锁在抢红包的步骤一、2不作加锁判断,在步骤3的时候才作加锁判断版本号。
能够看到,乐观锁在加锁失败的时候不挂起线程等待,避免了线程上下文频繁的切换,提升红包服务处理性能。
上面两种锁的形式都是基于对数据库的更新来作的,在大请求高并发的时候,频繁的存取数据库,尤为是乐观锁重试会对数据库产生很大的冲击,在实际生产环境要尽可能减小对数据库的访问。
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它能够用做数据库、缓存和消息中间件。也能够用redis实现分布式锁,与数据库交互两次:第一次获取红包余额,第二次抢完更新红包状态。抢红包和中间过程更新操做都在内存中进行,这可比数据库操做快了几个数量级,显著改善服务并发性能。
redis分布式锁:
利用Redis的SET操做在内存中保存key-value键值对,加锁就是获取这个键值对的值,解锁就是删除这个键值对。
分布式锁也不阻塞线程,关于这种分布式锁的实现不在这里展开说明,能够参考我另外一篇公众号文章: redis分布式锁的3种实现方式分析**,**详细分析了几种分布式锁特色和利弊。
原创不易,看到这里动动手指,各位的「三连」是对我持续创做的最大支持,咱们下篇文章再见。
能够微信搜索公众号「 后端技术学堂 」回复「资料」有我给你准备的各类编程学习资料。文章每周持续更新,咱们下期见!