Blog

学术套话与废话

Content #

哪怕是相当优秀的当代经济学家和历史学家,他们也会在自己的文章中使用“我们将会看到”(as we will see)这类常见的学术套话,同样会在报纸上写出“稍后详细介绍”(more on that later)这种对读者来说毫无意义的废话。

然而,事实上,这类写法,你在阿尔弗雷德·马歇尔(Alfred Marshall, 1842—1924,英国经济学家)、阿克顿男爵(Lord Acton,1834—1902,英国历史学家)、约翰·梅纳德·凯恩斯(John Maynard Keynes,1883—1946,英国经济学家)和A. J. P.泰勒(A. J. P. Taylor,1906—1990,英国历史学家)的笔下是绝不会看到的。

1969年,经济学家沃尔特·萨兰特(Walter Salant)发表文章《经济写作与阅读》(Writing and Reading in Economics),专门阐述了这件事。1978年, J. K.加尔布雷思(J. K. Galbraith,美国经济学家)写了一篇名为《写作、打字和经济学》(Writing, Typing and Economics)的文章,并引用了小说家海明威(Hemingway)挖苦垮掉派小说家杰克·凯鲁亚克(Jack Kerouac)的一句话:“那不是写作,那只是打字。”可以说,现在经济类、历史类、商业类、政府与军队服务等领域的许多文章,连打字都算不上。

From #

带标签的模版字符串(Tagged Templates)

Content #

const name = "why";
const age = 18;
const height = 1.88;
function foo(arr, arg1, arg2, arg3) {
  console.log(arr, arg1, arg2, arg3);
}
foo``;
//[ '' ] undefined undefined undefined
foo`my name is ${name},age is ${age},height is ${height}`;
//[ 'my name is ', ',age is ', ',height is ', '' ] why 18 1.88
foo`my name is ${name},double age is ${age * 2},height is ${height}`;
//[ 'my name is ', ',double age is ', ',height is ', '' ] why 36 1.88

标签模板字符串执行结果:

  1. 函数的第一个参数为数组,是模板字符串中的字符串被${}切割成的数组
  2. 除了第一个后的参数依次为模板字符串中${}的值

From #

TCC与XA规范的区别

Content #

1.TCC 是个业务层面的分布式事务协议,而 XA 规范是数据层面的分布式事务协议,这也是 TCC 和 XA 规范最大的区别。

2.TCC 与业务耦合紧密,在实际场景使用时,需要我们根据场景特点和业务逻辑来设计相应的预留、确认、撤销操作,相比 MySQL XA,有一定的编程开发工作量。

  1. 本质上而言,TCC 是一种设计模式,也就是一种理念,它没有与任何技术(或实现)耦合,也不受限于任何技术,对所有的技术方案都是适用的。

最后,因为 TCC 是在业务代码中编码实现的,所以,TCC 可以跨数据库、跨业务系统实现资源管理,满足复杂业务场景下的事务需求,比如, TCC 可以将对不同的数据库、不同业务系统的多个操作通过编码方式,转换为一个原子操作,实现事务。

另外,因为 TCC 的每一个操作对于数据库来讲,都是一个本地数据库事务,那么当操作结束时,本地数据库事务的执行也就完成了,所以相关的数据库资源也就被释放了,这就能避免数据库层面的二阶段提交协议长时间锁定资源,导致系统性能低下的问题。

Viewpoints #

From #

加餐 | TCC如何实现指令执行的原子性?

如何通过TCC指令执行的原子性

Content #

当接收到外部指令时,需要实现操作 1、2、3,其中任何一个操作失败,都需要暂停指令执行,将系统恢复到操作未执行状态,然后再重试。

其中,操作 1、2、3 的含义具体如下。

  1. 操作 1:生成指定 URL 页面对应的图片,并持久化存储。
  2. 操作 2:调用内部系统 1 的接口,禁用指定域名的访问权限。
  3. 操作 3:通过 MySQL XA 更新多个数据库的数据记录。

那么我是如何使用 TCC 来解决这个问题的呢?

答案是我在实现每个操作时,都会分别实现相应的预留、确认、撤销三操作。

首先,因为操作 1 是生成指定 URL 页面对应的图片,可以这么实现 TCC 三操作。

  1. 预留操作:生成指定页面的图片,并存储到本地。
  2. 确认操作:更新操作 1 状态为完成。
  3. 撤销操作:删除本地存储的图片。

其次,因为操作 2 是调用内部系统 1 的接口,禁用该域名的访问权限,那么,我是这么实现 TCC 三操作的。

  1. 预留操作:调用的内部系统 1 的禁用指定域名的预留接口。这时我们先通知系统 1 预留相关的资源。
  2. 确认操作:调用的内部系统 1 的禁用指定域名的确认接口。我们执行禁用域名的操作,这时,禁用域名的操作的生效了。
  3. 撤销操作:调用的内部系统 1 的禁用指定域名的撤销接口。我们撤销对该域名的禁用,并通知内部系统 1 释放相关的预留资源。

最后,操作 3 是通过 MySQL XA 更改多个 MySQL 数据库中的数据记录,并实现数据更新的事务。我是这么实现 TCC 三操作的:

  1. 预留操作:执行 XA START 和 XA END 准备好事务分支操作,并调用 XA PREPARE,执行二阶段提交协议的提交请求阶段,预留相关资源。
  2. 确认操作:调用 XA COMMIT 执行确认操作。
  3. 撤销操作:调用 XA ROLLBACK 执行回滚操作,释放在 Try 阶段预留的资源。

可以看到,确认操作是预留操作的下一个操作,而撤销操作则是用来撤销已执行的预留操作对系统产生的影响,类似在复制粘贴时,我们通过“Ctrl Z”撤销“Ctrl V”操作的执行,就像下图的样子。而这是理解 TCC 的关键。

...

什么是TCC

Content #

TCC 包含的预留、确认或撤销这 2 个阶段:

  1. Try 是指预留,它和二阶段提交协议中,提交请求阶段的操作类似,系统会将需要确认的资源预留、锁定,确保确认操作一定能执行成功。

  2. Confirm 是指确认,它呢和二阶段提交协议中,提交执行阶段的操作类似,系统将最终执行的操作。

  3. Cancel 是指撤销,比较像二阶段提交协议中的回滚操作,具体指系统将撤销之前预留的资源,也就是撤销已执行的预留操作对系统产生的影响。

二阶段提交协议和 TCC 的目标,都是为了实现分布式事务,这也就决定了它们“英雄所见略同”,在思想上是类似的,但这两个算法解决的问题场景是不同的,一个是数据层面,一个是业务层面,这就决定了它们在细节实现是不同的。

Viewpoints #

From #

加餐 | TCC如何实现指令执行的原子性?

通过MySQL XA实现分布式事务

Content #

  1. 创建一个唯一的事务 ID(比如 xid),来唯一标识事务,并调用“XA START”

和“XA END”来定义事务分支对应的操作: (比如 INSERT into operation_table SET id = 100, op = ‘get-cdn-log’)。

  1. 执行“XA PREPARE”命令,来执行二阶段提交协议的提交请求阶段。
  1. 调用“XA COMMIT”来提交事务(或者“XA ROLLBACK”回滚事务)。这样就实现了全局事务的一致性了。

可以看到,客户端在扮演事务管理器的角色,而 MySQL 数据库就在扮演资源管理器的角色。

如果你要开启 MySQL 的 XA 功能,必须设置存储引擎为 InnoDB。

能否将“XA END”和“XA PREPARE”合并到一起呢?答案是不能,因为在“XA END”之后,是可以直接执行“XA COMMIT”的,也就是一阶段提交(比如当共享资源变更只涉及到一个 RM 时)。

MySQL XA 性能不高,适合在并发性能要求不高的场景中使用。

Viewpoints #

From #

加餐 | MySQL XA是如何实现分布式事务的?

MySQL XA规范

Content #

提到 XA 规范,就不得不说 DTP 模型( Distributed Transaction Processing),因为 XA 规范约定的是 DTP 模型中 2 个模块(事务管理器和资源管理器)的通讯方式,那 DTP,就是分布式事务处理,就像下图的样子:

为了帮助你更好的理解 DTP 模型,我来解释一下 DTP 各模块的作用。

  1. AP:应用程序(Aplication Program),一般指事务的发起者(比如数据库客户端或者访问数据库的程序),定义事务对应的操作(比如更新操作 UPDATE executed_table SET status = true WHERE id=100)。

  2. RM:资源管理器(Resource Manager),管理共享资源,并提供访问接口,供外部程序来访问共享资源,比如数据库,另外 RM 还应该具有事务提交或回滚的能力。

  3. TM:事务管理器(Transaction Manager),TM 是分布式事务的协调者。TM 与每个 RM 进行通信,协调并完成事务的处理。

应用程序访问、使用资源管理器的资源,并通过事务管理器的事务接口(TX interface)定义需要执行的事务操作,然后事务管理器和资源管理器会基于 XA 规范,执行二阶段提交协议。

XA 规范约定了事务管理器和资源管理器之间双向通讯的接口规范,并实现了二阶段提交协议:

为了帮你更好地理解这个过程,咱们一起走下流程,加深下印象:

  1. AP(应用程序)联系 TM(事务管理器)发起全局事务;
  2. TM 调用 ax_open() 建立与资源管理器的会话;
  3. TM 调用 xa_start() 标记事务分支(Transaction branch)的开头;
  4. AP 访问 RM(资源管理器),并定义具体事务分支的操作,比如更新一条数据记录(UPDATE executed_table SET status = true WHERE id=100)和插入一条数据记录(INSERT into operation_table SET id = 100, op = ‘get-cdn-log’);
  5. TM 调用 xa_end() 标记事务分支的结尾;
  6. TM 调用 xa_prepare() 通知 RM 做好事务分支提交的准备工作,比如锁定相关资源,也就是执行二阶段提交协议的提交请求阶段;
  7. TM 调用 xa_commit() 通知 RM 提交事务分支(xa_rollback() 通知 RM 回滚事务),也就是执行二阶段提交协议的提交执行阶段;
  8. TM 调用 xa_close() 关闭与 RM 的会话。

你可以这么理解:xa_start() 和 xa_end() 在准备和标记事务分支的内容,然后调用 xa_prepare() 和 xa_commit()(或者 xa_rollback())执行二阶段提交协议,实现操作的原子性。在这里需要你注意的是,这些接口需要按照一定顺序执行,比如 xa_start() 必须要在 xa_end() 之前执行。

...

盈余公积与未分配利润的区别

Content #

公司并没有把自己赚到的所有钱都分给股东,还留下了一部分。这一部分也被放在两个项目里来计算,一个项目是盈余公积,另一个项目是未分配利润。这两者是如何区分的?

盈余公积是企业按照规定从净利润中提取的各种积累资金。中国的公司法规定,一家公司有了盈利之后,必须留存至少10%作为盈余公积。

简单说来,盈余公积是法律不让我们分配的利润,而未分配利润是企业自己不想分的利润。

最优的独特性(optimal distinctive)

Content #

心理学家玛丽莲·布鲁尔(Marilynn Brewer)提出了一套有影响力的理论。一方面,我们想要融入人群,我们寻求关系、凝聚力、社区、归属感、包容感,以及与他人的亲密关系;另一方面,我们又想要与众不同,我们寻求独特性、区别性和个体性。当我们在社会中探索时,这两种动机经常会发生冲突。我们对于一个团体的归属感越强,失去独特性的风险就越大。我们越是努力地将自己与别人区别开,失去归属感的风险就越大。我们如何能调和这种矛盾?

解决方案就是,既追求一致,同时保留差异。布鲁尔将这种原则称为最优的独特性(optimal distinctive):我们寻找融入的方法,同时保持与众不同。要想追求最优的独特性,普遍的方法就是加入一个独特的群体。加入一个拥有共同兴趣、身份认同、目标、价值、技能、性格或经验的团体给了我们一种联系感和归属感。与此同时,加入一个与其他群体明显不同的群体,也可以给我们一种独特感。研究显示,人们对于那些享有独特相似点的人和群体,有着更强烈的认同感。越罕见的群体、价值观、兴趣、技能或经历,其联结的形成就越容易。此外,研究还表明,人们在提供最优相似性的群体中更加快乐,这可以同时给他们一种包容感和独特感。正是这些群体,让我们感到最骄傲,感受到了最多的凝聚力和价值。

From #

现代人类行为

Content #

人类学家把那次最终的思维转变称为“现代人类行为”的发展。什么是“现代人类行为”?发生在什么时候?

他们所说的“现代人类行为”并不是指购物或者边看体育比赛边喝酒精饮料;他们指的是那些复杂的符号化思考行为,正是这种思维活动最终促使人类文化产生。对于这一行为是在什么时候发生的尚存有争议,但人们普遍接受的转变时间是在公元前4万年左右。

From #