Blog

ABA问题

Content #

多线程编程中的ABA问题指的是什么?

下面的操作序列会导致ABA问题:

  • Process P1 reads value A from shared memory,
  • P1 is preempted, allowing process P2 to run,
  • P2 modifies the shared memory value A to value B and back to A before preemption,
  • P1 begins execution again, sees that the shared memory value has not changed and continues.

一个例子:从列表中删除一个元素,再添加一个元素。基于Most Recently Used分配算法,指向新添加元素的指针会和原来指向被删除元素的指针相同。于是产生ABA问题。

From #

订单系统的ABA问题

Spurious Wakeup

Content #

A spurious wakeup happens when a thread wakes up from waiting on a condition variable that’s been signaled, only to discover that the condition it was waiting for isn’t satisfied.

It’s called spurious because the thread has seemingly been awakened for no reason. But spurious wakeups don’t happen for no reason: they usually happen because, in between the time when the condition variable was signaled and when the waiting thread finally ran, another thread ran and changed the condition. There was a race condition between the threads, with the typical result that sometimes, the thread waking up on the condition variable runs first, winning the race, and sometimes it runs second, losing the race.

...

sub:GC

GC #

基本概念 #

Copy GC #

G1 #

Pauseless GC #

垃圾收集器的不可能三角

Content #

什么是垃圾收集器的“不可能三角”?

衡量垃圾收集器的三项最重要的指标是:

  1. 内存占用(Footprint)
  2. 吞吐量(Throughput)
  3. 延迟(Latency)

三者共同构成了一个“不可能三角”。三者总体的表现会随技术进步而越来越好,但是要在这三个方面同时具有卓越表现的“完美”收集器是极其困难甚至是不可能的,一款优秀的收集器通常最多可以同时达成其中的两项。

From #

IOPS 和吞吐量(Throughput)

Content #

衡量磁盘性能的两个常见的指标 IOPS 和吞吐量(Throughput)分别是什么含义?两者之间有什么关联?

IOPS 是 Input/Output Operations Per Second 的简称,也就是每秒钟磁盘读写的次数,这个数值越大,当然也就表示性能越好。

吞吐量(Throughput)是指每秒钟磁盘中数据的读取量,一般以 MB/s 为单位。这个读取量可以叫作吞吐量,有时候也被称为带宽(Bandwidth)。

IOPS 和吞吐量之间是有关联的,在 IOPS 固定的情况下,如果读写的每一个数据块越大,那么吞吐量也越大,它们的关系大概是这样的:

吞吐量 = 数据块大小 *IOPS。

From #

IOPS

用面向对象的术语来对狗咬人建模

Content #

狗咬人这事行为用面向对象的术语应该怎么来建模?是狗类中有咬方法吗?

如果狗咬了后,狗本身的状态不需要发生变化,那么这个方法写在狗类中就是不合理的。而应该是在Human类中添加hurt方法。狗则提供damage。面向对象建模并不能完全等同于自然语言的描述。

From #

将付出行为内化为自我认同的一部分

Content #

在过去的35年中,巴特森和同事开展的一项研究显示,当人们付出时,如果他们受到外部因素的影响,比如晋升,那么他们就不会将自己视为付出者。与之对应的另外一种做法,则会将自己认定为是付出者。这是什么做法?

如果人们反复地做出个人选择,帮助他人,他们就会开始将付出行为内化为自我认同的一部分。对于一些人来说,这种变化产生于一种积极的认知失调过程:一旦我自愿做出了付出的决定,我就没法改变这个行为,因此为了保持一致和避免伪善,最简便的办法就是认为自己是一个付出者。对于其他人来说,这种内化过程是从观察他们自己的行为中学到的。借用作家E.M.福斯特(E. M. Forster)的一句话:“除非我看到自己的所作所为,否则我怎么能知道自己是个什么样的人?”

From #

待摊费用

Content #

什么是待摊费用?常见的待摊费用有哪些?

小张的公司购买了价值6万元的办公用品,这批办公用品足够小张的公司使用6个月的时间。

但这批办公用品无疑会在6个月之内用光,这6万元最终将会变成小张公司这6个月的办公费用。它最初的确是一笔资产,但随着企业的正常运营和时间的流逝,它最终变成了一笔费用,这就叫待摊费用。比如预付的房租、预付的广告费用,甚至开办一家企业所需要的开办费,都是待摊费用。

Percolator对2PC的改进

Content #

让我们对比 2PC 的问题,来看看 Percolator 模型有哪些改进。

  1. 数据不一致

2PC 的一致性问题主要缘自第二阶段,不能确保事务管理器与多个参与者的通讯始终正常。

但在 Percolator 的第二阶段,事务管理器只需要与一个分片通讯,这个 Commit 操作本身就是原子的。所以,事务的状态自然也是原子的,一致性问题被完美解决了。

  1. 单点故障

Percolator 通过日志和异步线程的方式弱化了这个问题。

一是,Percolator 引入的异步线程可以在事务管理器宕机后,回滚各个分片上的事务,提供了善后手段,不会让分片上被占用的资源无法释放。

二是,事务管理器可以用记录日志的方式使自身无状态化,日志通过共识算法同时保存在系统的多个节点上。这样,事务管理器宕机后,可以在其他节点启动新的事务管理器,基于日志恢复事务操作。

Percolator 模型在分布式数据库的工程实践中被广泛借鉴。比如,分布式数据库 TiDB,完全按照该模型实现了事务处理;CockroachDB 也从 Percolator 模型获得灵感,设计了自己的 2PC 协议。

Viewpoints #

From #

09|原子性:2PC还是原子性协议的王者吗?

Percolator的流程

Content #

使用 Percolator 模型的前提是事务的参与者,即数据库,要支持多版本并发控制(MVCC)。

在转账事务开始前,小明和小红的账户分别存储在分片 P1 和 P2 上。

上图中的 Ming 代表小明,Hong 代表小红。在分片的账户表中各有两条记录,第一行记录的指针(write)指向第二行记录,实际的账户余额存储在第二行记录的 Bal. data 字段中。

Bal.data 分为两个部分,冒号前面的是时间戳,代表记录的先后次序;后面的是真正的账户余额。我们可以看到,现在小明的账户上有 4,900 元,小红的账户上有 300 元。

我们来看下 Percolator 的流程。

第一,准备阶段,事务管理器向分片发送 Prepare 请求,包含了具体的数据操作要求。

分片接到请求后要做两件事,写日志和添加私有版本。关于私有版本,你可以简单理解为,在 lock 字段上写入了标识信息的记录就是私有版本,只有当前事务能够操作,通常其他事务不能读写这条记录。

你可能注意到了,两个分片上的 lock 内容并不一样。

主锁的选择是随机的,参与事务的记录都可能拥有主锁,但一个事务只能有一条记录拥有主锁,其他参与事务的记录在 lock 字段记录了指针信息“primary@Ming.bal”,指向主锁记录。

准备阶段结束的时候,两个分片都增加了私有版本记录,余额正好是转账顺利执行后的数字。

第二,提交阶段,事务管理器只需要和拥有主锁的分片通讯,发送 Commit 指令,且不用附带其他信息。

分片 P1 增加了一条新记录时间戳为 8,指向时间戳为 7 的记录,后者在准备阶段写入的主锁也被抹去。这时候 7、8 两条记录不再是私有版本,所有事务都可以看到小明的余额变为 2,700 元,事务结束。

你或许要问,为什么在提交阶段不用更新小红的记录?

Percolator 最有趣的设计就是这里,因为分片 P2 的最后一条记录,保存了指向主锁的指针。其他事务读取到 Hong7 这条记录时,会根据指针去查找 Ming.bal,发现记录已经提交,所以小红的记录虽然是私有版本格式,但仍然可视为已经生效了。

当然,这种通过指针查找的方式,会给读操作增加额外的工作。如果每个事务都照做,性能损耗就太大了。所以,还会有其他异步线程来更新小红的余额记录,最终变成下面的样子。

Viewpoints #

From #

09|原子性:2PC还是原子性协议的王者吗?

...