在 《企业应用架构模式》 中 提到了 乐观锁定,

用 时间戳 来 判定 交易 是否有效, 避免 传统事务 的 表锁定 造成 的 瓶颈 。

在 现在的 大并发 的 大环境下, 传统事务 及其 表锁定 以及 事务带来 的 性能消耗, 确实 不能适应 当今 的 大并发 的 场景 了 。

感觉 传统事务 也就只能用在 办公系统 了,   哈哈哈哈 。

但是 传统事务 的 表锁定 是 合理的, 表锁定 使得 事务中 其它 线程 不能 读写 表 。

不能 写, 这个容易理解, 不能 读 是怎么回事 ?

因为 读取表的结果 会 作为 系统 决策行为 的 依据, 所以 也不能 读 。

比如, 一个商品已经卖出去了, 就不能再卖给其它用户 。

那么, 用 乐观锁定 能解决这些问题吗 ?

乐观锁定 的 提出 是 很有意义的,

但是不太靠得住,  为什么呢 ?

时间戳 通常 取到 毫秒, 但 如果 并发密度 超过了 毫秒级, 达到了 比如 微秒级,  那 ?

当然 理论上 可以随机的取 其中 一个用户 作为 成功者, 其他用户作为 失败者(牺牲者?) 。

不过 理论上, 这还不是一种 完备 的 做法 。

我们再来看看 Redis 锁定,

Redis 提供了 对 数据(对象) 的 锁(Lock), 以及 队列 Queue 等 数据类型, 以及 对 Queue 的 Block 操作 。

我们可以利用 Redis 来锁定 某个 ID 的 业务实体 (某个 订单号 的 订单), 然后 对 这个 业务实体(订单) 进行 相关的操作(事务 / 交易),

这样 达到 多个 线程(用户) 对 同一个 订单 的 操作(交易) 顺序进行  。

这种做法 的 实质 是 行锁定 ,  那为什么不通过 数据库 来实现 行锁定 呢  ?

因为 我 不知道 数据库 行锁定 的 语法,,,,,,

其次, 数据库 行锁定 的 实现 会 更加 复杂 和 重量,

Redis 的 对象锁 则 简单 而 轻量 。

事实上, 如果 把 上述过程 简化 下来,

我们 只是 需要 有一个  “Flag”  在 Redis 里 可以 供 多台 Server 的 线程间 同步协作 即可 。

严格的讲, 在 负载均衡 (集群), 即 多台 Server  的 情形下 才需要使用  Redis (分布式缓存) ,

如果 是 单台 Server ,  则 使用 进程内 的 变量 来 作为 “Flag”  Lock  即可 。

此时, 情况 则 退化为 进程内 多线程 之间的 同步协作 。

同时, 严格的讲, Redis 只需要提供一个 “Flag”, 或者说, Redis 只需要提供一个 锁机制 ,

并不需要 将 具体的 业务数据(对象) 保存 到 Redis,

进行 一笔交易 时, 不需要 到 Redis 查找 业务对象(比如 订单), 如果查不到再到 数据库 查, 更新时 先更新 Redis, 再更新 数据库 ,

没有必要这样 。

Redis 只要提供 “Flag” Lock 来 确保 顺序进入(同步协作),  具体的操作直接 读写 数据库 即可 。

所以, Redis 的 真正意义 在于 共享内存, 而不是 数据缓存 。

可以看看我昨天写的  《论 业务系统 架构 的 简化 (二) 用 关系数据库 作 缓存》   https://www.cnblogs.com/KSongKing/p/9928412.html

除了 锁, 事务 还有 另一方面,  数据完整性 。

比如, 更新 A, B, C 三张表, A, B 成功, C 失败, 于是事务会回滚, A, B 恢复原来的数据 。

要实现 数据完整性, 需要 表锁定 和 事务日志(这会带来 性能消耗),

可见,

数据完整性 同样也会成为 大并发 的 瓶颈 。

所以,我们这里 提出 一个  “乐观事务”  概念,

即 对于 每次交易, 都是 Insert , 而不会 反复 的 去 Update 。

假如一个交易 要 更新 3 个表, A 表 为 主表, B, C 表通过 A 表 的 ID 关联,

那么, 这个交易 对 A,B,C  3 个表都是  Insert  操作, 在 最后 事务成功 时 将 A 表里的 “生效” 栏位 更新 为  “Y”,

以此 表示 事务成功 。

显然, 这种做法 并不是对 所有场合 都适用, 它会让一些 小场景 变得麻烦 。

但是, 对于 前端 海量 用户 海量 并发 的 场景, 可以使用 这种做法 。

P :   我们大概可以把   每秒 100万 ~ 1000万 的 交易量 称为 “海量”,  把  每秒 1000万 以上 的 交易量 称为 “天量”  。

Redis 锁  +  乐观事务  =  新时代事务

我们来看一下 新时代事务 处理 3 个场景 :

1  订单(交易)

2  秒杀

3  商品库存计数

1  订单(交易),

用 Redis 锁 来 锁定, 用 乐观事务 执行 更新数据,  具体的 大家 自己想象 吧

2  秒杀

用 Redis 存一个 对象 记录 被 哪个 用户秒杀, 同时 加上 Redis 锁, 这样 用户 就可以 顺序 的 获取这个对象,

第一个获得这个对象的用户 就 秒杀 成功,  并更新这个 对象 的 状态 表示 秒杀成功 。

3  商品库存计数

同 Redis 存一个 对象 记录 库存量, 用户将 商品 放入 购物车 则 对象.库存量 - 1, 用户将 商品 从 购物车 删除 则 对象.库存量 + 1 ,

通过 对象锁 来 确保 用户顺序 获取对象 查看 和 更新 库存量 。

可以看看我前几天写的  《一个类似 Twitter 雪花算法 的 连续序号 ID 产生器 SeqIDGenerator》  https://www.cnblogs.com/KSongKing/p/9918412.html

通常, 一个实体 会 对应一张表,

我们以 订单 为例,

一笔 订单 对应 订单表 里的 一笔资料,

订单表 会有一张 对应的 订单_Trans  表,  用来记录 发生 在 订单 上的 乐观事务,

订单_Trans 表 会有一个 ID ,  表示  Transaction ID ,

订单_Trans 表 同时还包含  订单 需要更新 的 栏位,

这样, 发生 一次 事务 时,  会向 订单_Trans 表 insert 一笔资料,  栏位 的 值 是 订单 本次 更新的 栏位 的 值,

事务 成功 后, 会将 订单 表 里的  “trans”   栏位 更新为 这次 事务 的 ID,  即 订单_Trans 表 的  ID ,

这样, 通过      订单.Trans = 订单_Trans.ID      关联, 可以查询到 订单 在 本次 事务 更新后的 栏位 的 值 。

一笔订单 在 订单_Trans 表 中可以对应 多笔 事务记录,  这些 事务记录,  有成功的, 也有不成功的 。

乐观事务 的 关键 在于 最后只能 更新 一张表 的  (一个)栏位 来 决定 事务是否成功,

如果要 更新 多个 表, 那又 回到 传统事务 了 。

所以, 这就看 针对性 的 设计 。

对于  淘宝 天猫   这样的 海量购物, 应该设计为 单项递增数据 的 架构, 也就是 只 insert ,  不 update ,

但问题是 如果 一个 交易 里 要 insert 多个 表 呢  ?

也许可以用 乐观事务     A 表 关联 B 表, B 表 关联 C 表,  ……

这样只需要 最后 更新 A 表里的一个 生效 栏位 ,  就可以 表示 事务 是否成功 。

因为 可以 根据 A 表 关联 到 B 表 , B 表 关联 到 C 表 ,

或者有一个  Trans 表,  通过 Trans 表 的 ID  (Trans ID)  来 关联  A, B, C  表 ,

这样可以 查询出     某一个 事务(Trans ID)     在  A, B, C 表 里  insert  的 资料,

然鹅   。

不过 说不定 这种方法 真的 有人在用 喔  ~!

数据完整性 最好 还有由 数据库 来实现,  这才是合理的 。

关键在于,

数据库 应该使用    行锁定   来 实现 数据完整性 。

就是说, 我们应该让 数据库 用 行锁定 来 执行 事务 。

淘宝 天猫 应该 自己 已经对 数据库 做过这种 优化了 。

也就是说, 淘宝 天猫 的 数据库 的 事务 是用 行锁定 的 方式 执行的 ,

当然, 这只是我的 猜测,   啊哈哈哈哈 。

Redis 锁定       +        数据库 行锁定 事务 (行级事务)      +        数据库 使用 固态硬盘

这样 来 应对 大并发,  你觉得呢 ?

论 大并发 下的 乐观锁定 Redis锁定 和 新时代事务的更多相关文章

  1. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  2. 大并发连接的oracle在Linux下内存不足的问题的分析

    大并发连接的oracle在Linux下内存不足的问题的分析 2010-01-28 20:06:21 分类: Oracle 最近一台装有Rhel5.3的40G内存的机器上有一个oracle数据库,数据库 ...

  3. 大压力下Redis参数调整要点

    调整以下参数,可以大幅度改善Redis集群的稳定性: 为何大压力下要这样调整? 最重要的原因之一Redis的主从复制,两者复制共享同一线程,虽然是异步复制的,但因为是单线程,所以也十分有限.如果主从间 ...

  4. 【转载】.NET中锁6大处理方法 悲观乐观自己掌握

    我们为什么需要锁? 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这就会产生冲突,这个就是著名的并发性问题. 图 1 并行性问题漫画 如何解决并发性问题? 借助正确的锁定策略可以解决并发性 ...

  5. 《.NET 5.0 背锅案》第7集-大结局:捉拿真凶 StackExchange.Redis.Extensions 归案

    第1集:验证 .NET 5.0 正式版 docker 镜像问题 第2集:码中的小窟窿,背后的大坑,发现重要嫌犯 EnyimMemcachedCore 第3集-剧情反转:EnyimMemcachedCo ...

  6. 大并发server架构 && 大型站点架构演变

    server的三条要求: 高性能:对于大量请求,及时高速的响应 高可用:7*24 不间断,出现问题自己主动转移.这叫fail over(故障转移) 伸缩性:使用跨机器的通信(TCP) 另外不论什么网络 ...

  7. .net core 下使用StackExchange的Redis库访问超时解决

    原文:.net core 下使用StackExchange的Redis库访问超时解决 目录 问题:并发稍微多的情况下Redis偶尔返回超时 给出了参考网址? 结论 小备注 引用链接 问题:并发稍微多的 ...

  8. 处理大并发之五 使用libevent利器bufferevent

    转自:http://blog.csdn.net/feitianxuxue/article/details/9386843 处理大并发之五 使用libevent利器bufferevent 首先来翻译一段 ...

  9. ab测试大并发错误

    转载自http://xmarker.blog.163.com/blog/static/226484057201462263815783 apache 自带的ab工具测试,当并发量达到1000多的时候报 ...

随机推荐

  1. pragma comment的使用 pragma预处理指令详解

    pragma comment的使用 pragma预处理指令详解   #pragma comment( comment-type [,"commentstring"] ) 该宏放置一 ...

  2. Linux平台搭建-----C语言

    下面内容是新手上路,各位高手路过勿喷!因为我第一次发布,可能页面设置或者其他做的不好,还请见谅~该文章只是作为我学习C语言的笔记以及记录学习进程的. 零基础学习C语言---搭建Linux平台开发环境 ...

  3. springsecurity基于数据库验证用户

    之前的springsecurity程序都是将数据存放在内存中的,通过 <security:user-service> <security:user name="user&q ...

  4. 常见无线DOS攻击

    记录下自己最近一段时间对无线渗透学习的笔记. 无线DOS就是无线拒绝服务攻击.主要包括以下几种攻击类型:Auth Dos攻击.Deauth Flood攻击.Disassociate攻击及RF干扰攻击等 ...

  5. vue优势

    Vue.js是一个轻巧.高性能.可组件化的MVVM库,同时拥有非常容易上手的API: 我们都知道单页面应用:页面切换快 ,首屏时间稍慢,SEO差        js 渲染 (多页面应用:  首屏时间快 ...

  6. 2019-04-01-day023-对象实例的反射实例化

    学习方法 学练改管测 听别人说 读 input 自己说 自己写 output 解决语法错误 解决逻辑错误 ##内容回顾 ##继承 多态 封装 property classmethod staticme ...

  7. 【Python】多线程-1

    #练习:创建一个线程 from threading import Thread import time def run(a = None, b = None) : print a, b time.sl ...

  8. EPOCH, BATCH, INTERATION

    CIFAR10 数据集有 50000 张训练图片,10000 张测试图片.现在选择 Batch Size = 256 对模型进行训练. 每个 Epoch 要训练的图片数量:  训练集具有的 Batch ...

  9. 大数据-01-安装Hadoop

    环境 服务器:ubuntu-16.04.3-desktop-amd64.iso 创建hadoop用户 sudo useradd -m hadoop -s /bin/bash 本文中会大量使用到sudo ...

  10. ix 混合索引

    raw_datas #DateFrame diff_index_list = [] #行index #多行所有列索引 raw_datas.ix[diff_index_list] #多行一列索引raw_ ...