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

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

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

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

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

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

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

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

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

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

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

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

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

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

我们再来看看 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. tensorflow-LSTM-网络输出与多隐层节点

    本文从tensorflow的代码层面理解LSTM. 看本文之前,需要先看我的这两篇博客 https://www.cnblogs.com/yanshw/p/10495745.html 谈到网络结构 ht ...

  2. subprocess(子进程模块)

    subprocess: 子进程模块 一个正在运行的程序叫做进程 一个进程 开启了另一个进程 这个被开启的程序叫做子ka进程 ###########################在cmd中执行#### ...

  3. Delphi直接实现分享图片功能

    procedure TCustomCameraViewDoc.ShareTextClick(Sender: TObject); var FSharingService: IFMXShareSheetA ...

  4. JAVA_全局配置文件(配置网址,url等等)_第一种方式

    一.概述 当使用httpClient调其他系统接口时,需要通过地址来发送post请求. 这时我们有不同的环境,那么就有两个问题. 1是地址不能写在代码中,而是要写在配置文件. 2是不同环境配置文件应该 ...

  5. es6 常用总结

    1.变量 let 声明的变量只在它所在的代码块有效,不允许重复声明 const 声明是一个只读的常量.一旦声明,常量的值就不能改变. const与let的作用域相同,只在声明所在的块级作用域内有效. ...

  6. [转]谈谈 Bias-Variance Tradeoff

    https://liam0205.me/2017/03/25/bias-variance-tradeoff/ 谢谢原作者! 谈谈 Bias-Variance Tradeoff 发表于 2017 年 0 ...

  7. [转] 带你彻底理解RSA算法原理

    http://blog.csdn.net/dbs1215/article/details/48953589 1. 什么是RSA RSA算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法 ...

  8. [转]ZooKeeper 集群环境搭建 (本机3个节点)

    ZooKeeper 集群环境搭建 (本机3个节点) 是一个简单的分布式同步数据库(或者是小文件系统) ------------------------------------------------- ...

  9. idea 中新建Servlet

    本文转载自 :itellij idea创建javaWeb以及Servlet简单实现  一.创建并设置javaweb工程 1.创建javaweb工程File --> New --> Proj ...

  10. drop redo logfile current报错

    目的:在安装完毕11.2.0.4版本Oracle单实例数据库后,对日志进行格式化,删除原日志组current状态,删除报错 #对于理论学习,而带来的理解命令,因此作为记录 #查询日志状态SYS > ...