Blog

键盘符号的读法

键盘符号的读法和使用 #

  1. ~ 波浪号tilde /’tildə/,源于西班牙语和葡语中的发音符号。a diacritical mark () placed over the letter n in Spanish to indicate a palatal nasal sound or over a vowel in Portuguese to indicate nasalization.(在西班牙语中放在字母n上的一个变音标记(),表示腭部的鼻音,或在葡萄牙语中放在元音上表示鼻音)这个符号该如何使用?是不是中文中的规范符号?好多科技论文中使用它表示区间,比如在表述孔隙度范围时,用到:煤岩层的孔隙度是2.3~7.8%。
  2. ! 感叹号exclamation mark/exclamation point/bang,无需多解释,在这个“咆哮体”盛行的时代,想不懂这个都难。
  3. # 汉语中因形似“井”,通常读作井号,真正的含义是数字符号(Number sign),如在一些国家‘#1’代表No.1的意思。在美式英语中一般称作pound sign,电话上的“#”叫做pound key,而加拿大英语则称之为number sign key;北美以外的其他英语国家一般称“#”为hash,相应的电话键叫做hash key。注意:数字符号(#)极易和乐谱中的升音符(? 读作sharp)相混淆。但是,乐谱的sharp和数字符号的字形不完全一样。标准数字符号(#)横线水平,而竖线向右倾斜;而乐谱的升号(?)为了在五线谱中容易识别,横线改为斜向上但竖线垂直。我猜此时有人就会举出一个极好的反例来否定上述说法,那就是C#(C Sharp)。的确,乍一看确实不相符!但事实上,C#并不违背上述结论,C Sharp中符号Sharp的创意正是来源于升音符?在乐谱中的含义——紧跟其后的音符的音高比实际标定的高半音,表示技术进一步提升之意(要不直接把C#本土化,翻译成“C优”算了^_^,这个命名方法有点类似于 C++中“++”表示变量增1)。由于“?”在计算机显示、输入中不方便,因此在书写体中用“#”代替“?”,但读音保持不变。于是就出现了书写成“C#”但念作“C Sharp”的情形,了解渊源之后发现其实并不矛盾。问题来了,8号煤到底是写成 #8 还是8# ?国内多用8#。
  4. $ dollar/peso sign,我们通常把这个当作美元(USD)的符号,但拉丁美洲一些国家的人们会认为“\(” 代表比索(peso),所以,不引起误解,最好用“US\)”代表美元。这个符号的起源还存在争议,其中有一种说法是这样的:在18世纪末,货币单位比索的手写缩写符号是“ps”,随着时间推移,p和s 感情渐进、关系日益密切,最后重叠在一起形成了现在的“$”。
  5. % 百分号,percent sign。
  6. ^ a读caret,表示间距符 “^ ”或 “?”,也称作wedge, up-arrow, hat,数学中通常叫做hat;b读circumflex (^),是发音符号,常见用法如?。 a mark used by an author or editor to indicate where something is to be inserted into a text
  7. & ampersand/and,单词“and”的简写形式。
  8. * asterisk/star,计算机和数学中称作“star”更常见。
  9. () round brackets/open brackets; [ ] square brackets/closed brackets; { } curly brackets/definite brackets; < > angle brackets/triangular brackets,除了用作尖括号,也用作不等号,小于号< (less-than),大于号>(greater-than)。
  10. / 斜杠,slash,为与“\”相区别,通常也叫forward slash。
  11. \ 反斜杠,backslash。
    • 加号,plus sign; - 减号,minus sign。
    • – — dash,英文中dash

Viewpoint #

From #

幂等框架如何应对三种不同类型的异常

幂等框架如何应对三种不同类型的异常 #

在正常情况下,幂等框架的处理流程是比较简单的,调用方生成幂等号,传递给实现方,实现方记录幂等号或者用幂等号判重。但是,幂等框架要处理的异常情况很多,这也是设计的复杂之处和难点之处。

我们针对三种不同类型的异常,讲解了幂等框架的应对思路。

对于业务代码异常,为了让幂等框架尽可能的灵活,低侵入业务逻辑,发生异常(不管是业务异常还是系统异常),是否允许再重试执行业务逻辑,交给开发这块业务的工程师来决定。

对于业务系统宕机,对于这种极少发生的异常,在工程中,我们能够做到,在出错时能及时发现问题、能够根据记录的信息人工修复,就可以了。所以,我们建议业务系统记录 SQL 的执行日志,在日志中附加上幂等号。这样我们就能在机器宕机时,根据日志来判断业务执行情况和幂等号的记录是否一致。

对于幂等框架异常,跟限流框架异常处理对策不同,在幂等逻辑执行异常时,我们选择让接口请求也失败,相应的业务逻辑就不会被重复执行了,业务就不会出错。毕竟接口请求失败,比业务执行出错,修复的成本要低很多。

虽然幂等框架要处理的异常很多,但考虑到开发成本以及简单易用性,我们对某些异常的处理在工程上做了妥协,交由业务系统或者人工介入处理。这样就大大简化了幂等框架开发的复杂度和难度。

Viewpoint #

From #

94 | 项目实战二:设计实现一个通用的接口幂等框架(设计)

toc:Organization

Content #

冯·诺依曼体系结构

进制与编码 #

计算校验码位数 4-3海明码的纠错原理 7-4海明码的计算原理 海明距离 Intel CPU体系中的各个总线 CPU是如何控制I/O设备的?

CPU #

乱序窗口 CPU的乱序执行 投机执行 分支预测技术(Branch Prediction) Pipeline Zap(Flush) CPU Store Buffer StoreBuffer对程序的影响 失效队列(Invalid Queue) 内存屏障与StoreBuffer 内存屏障与InvalidQueue 指令周期,CPU周期,时钟周期 超长流水线的性能瓶颈 流水线冒泡(Pipeline Bubble) 多发射和超标量 超线程(Hyper-Threading)技术 SIMD 中断、陷阱、故障和中止 上下文切换比函数调用更加复杂

缓存 #

缓存块(cache line) 缓存块的组织形式 缓存块替换策略 查看CPU缓存信息 伪共享 缓存一致性问题 缓存写策略 写直达(Write-Through) 写回(Write-Back) 写失效与写广播 CPU缓存中的事务串行化 MESI协议的四种基本状态 独占状态与共享状态 MESI协议 MESI有限状态机 cache与buffer这两个术语的区别

FPGA #

什么是FPGA 什么是ASIC FPGA的LUT电路 TCO与NRE

Memory #

toc:Hardware #

冯·诺依曼体系结构

冯·诺依曼体系结构 #

首先是一个包含算术逻辑单元(Arithmetic Logic Unit,ALU)和处理器寄存器(Processor Register)的处理器单元(Processing Unit),用来完成各种算术和逻辑运算。因为它能够完成各种数据的处理或者计算工作,因此也有人把这个叫作数据通路(Datapath)或者运算器。

然后是一个包含指令寄存器(Instruction Register)和程序计数器(Program Counter)的控制器单元(Control Unit/CU),用来控制程序的流程,通常就是不同条件下的分支和跳转。在现在的计算机里,上面的算术逻辑单元和这里的控制器单元,共同组成了我们说的 CPU。

接着是用来存储数据(Data)和指令(Instruction)的内存。以及更大容量的外部存储,在过去,可能是磁带、磁鼓这样的设备,现在通常就是硬盘。

最后就是各种输入和输出设备,以及对应的输入和输出机制。我们现在无论是使用什么样的计算机,其实都是和输入输出设备在打交道。个人电脑的鼠标键盘是输入设备,显示器是输出设备。我们用的智能手机,触摸屏既是输入设备,又是输出设备。而跑在各种云上的服务器,则是通过网络来进行输入和输出。这个时候,网卡既是输入设备又是输出设备。

任何一台计算机的任何一个部件都可以归到运算器、控制器、存储器、输入设备和输出设备中,而所有的现代计算机也都是基于这个基础架构来设计开发的。

而所有的计算机程序,也都可以抽象为从输入设备读取输入信息,通过运算器和控制器来执行存储在存储器里的程序,最终把结果输出到输出设备中。而我们所有撰写的无论高级还是低级语言的程序,也都是基于这样一个抽象框架来进行运作的。

可以说,冯·诺依曼体系结构确立了我们现在每天使用的计算机硬件的基础架构。因此,学习计算机组成原理,其实就是学习和拆解冯·诺依曼体系结构。

具体来说,学习组成原理,其实就是学习控制器、运算器的工作原理,也就是 CPU 是怎么工作的,以及为何这样设计;学习内存的工作原理,从最基本的电路,到上层抽象给到 CPU 乃至应用程序的接口是怎样的;学习 CPU 是怎么和输入设备、输出设备打交道的。

学习组成原理,就是在理解从控制器、运算器、存储器、输入设备以及输出设备,从电路这样的硬件,到最终开放给软件的接口,是怎么运作的,为什么要设计成这样,以及在软件开发层面怎么尽可能用好它。

Viewpoint #

From #

01 | 冯·诺依曼体系结构:计算机组成的金字塔

调用接口超时问题

调用接口超时问题 #

调用方访问公共服务平台的接口,会有三种可能的结果:成功、失败和超时。前两种结果非常明确,调用方可以自己决定收到结果之后如何处理。结果为“成功”,万事大吉。结果为“失败”,一般情况下,调用方会将失败的结果,反馈给用户(移动端 App),让用户自行决定是否重试。

但是,当接口请求超时时,处理起来就没那么容易了。有可能业务逻辑已经执行成功了,只是公共服务平台返回结果给调用方的时候超时了,但也有可能业务逻辑没有执行成功,比如,因为数据库当时存在集中写入,导致部分数据写入超时。总之,超时对应的执行结果是未决的。那调用方调用接口超时时(基于 Feign 框架开发的话,一般是收到 Timeout 异常),该如何处理呢?

如果接口只包含查询、删除、更新这些操作,那接口天然是幂等的。所以,超时之后,重新再执行一次,也没有任何副作用。不过,这里有两点需要特殊说明一下。

删除操作需要当心 ABA 问题。删除操作超时了,又触发一次删除,但在这次删除之前,又有一次新的插入。后一次删除操作删除了新插入的数据,而新插入的数据本不应该删除。不过,大部分业务都可以容忍 ABA 问题。对于少数不能容忍的业务场景,我们可以针对性的特殊处理。

除此之外,细究起来,update x = x+delta 这样格式的更新操作并非幂等,只有 update x=y 这样格式的更新操作才是幂等的。不过,后者也存在跟删除同样的 ABA 问题。

如果接口包含修改操作(插入操作、update x=x+delta 更新操作),多次重复执行有可能会导致业务上的错误,这是不能接受的。如果插入的数据包含数据库唯一键,可以利用数据库唯一键的排他性,保证不会重复插入数据。除此之外,一般我会建议调用方按照这样几种方式来处理。

第一种处理方式是,调用方访问公共服务平台接口超时时,返回清晰明确的提醒给用户,告知执行结果未知,让用户自己判断是否重试。不过,你可能会说,如果用户看到了超时提醒,但还是重新发起了操作,比如重新发起了转账、充值等操作,那该怎么办呢?实际上,对这种情况,技术是无能为力的。因为两次操作都是用户主动发起的,我们无法判断第二次的转账、充值是新的操作,还是基于上一次超时的重试行为。

第二种处理方式是,调用方调用其他接口,来查询超时操作的结果,明确超时操作对应的业务,是执行成功了还是失败了,然后再基于明确的结果做处理。但是这种处理方法存在一个问题,那就是并不是所有的业务操作,都方便查询操作结果。

第三种处理方式是,调用方在遇到接口超时之后,直接发起重试操作。这样就需要接口支持幂等。我们可以选择在业务代码中触发重试,也可以将重试的操作放到 Feign 框架中完成。因为偶尔发生的超时,在正常的业务逻辑中编写一大坨补救代码,这样做会影响到代码的可读性,有点划不来。当然,如果项目中需要支持超时重试的业务不多,那对于仅有几个业务,特殊处理一下也未尝不可。但是,如果项目中需要支持超时重试的业务比较多,我们最好是把超时重试这些非业务相关的逻辑,统一在框架层面解决。

对响应时间敏感的调用方来说,它们服务的是移动端的用户,过长的等待时间,还不如直接返回超时给用户。所以,这种情况下,第一种处理方式是比较推荐的。但是,对响应时间不敏感的调用方来说,比如 Job 类的调用方,我推荐选择后两种处理方式,能够提高处理的成功率。而第二种处理方法,本身有一定的局限性,因为并不是所有业务操作都方便查询是否执行成功。第三种保证接口幂等的处理方式,是比较通用的解决方案。

Viewpoint #

From #

93 | 项目实战二:设计实现一个通用的接口幂等框架(分析)

幂等号

幂等号 #

“幂等”到底是什么意思呢?放到接口调用的这个场景里,幂等的意思是,针对同一个接口,多次发起同一个业务请求,必须保证业务只执行一次。那如何判定两次接口请求是同一个业务请求呢?也就是说,如何判断两次接口请求是重试关系?而非独立的两个业务请求?比如,两次调用转账接口,尽管转账用户、金额等参数都一样,但我们也无法判断这两个转账请求就是重试关系。

实际上,要确定重试关系,我们就需要给同一业务请求一个唯一标识,也就是“幂等号”!如果两个接口请求,带有相同的幂等号,那我们就判断它们是重试关系,是同一个业务请求,不要重复执行。

幂等号需要保证全局唯一性。它可以有业务含义,比如,用户手机号码是唯一的,对于用户注册接口来说,我们可以拿它作为幂等号。不过,这样就会导致幂等框架的实现,无法完全脱离具体的业务。所以,我们更加倾向于,通过某种算法来随机生成没有业务含义的幂等号。

Viewpoint #

From #

93 | 项目实战二:设计实现一个通用的接口幂等框架(分析)

MongoDB名字的来历

MongoDB名字的来历 #

MongoDB 的名字需要解释一下。国内很多人觉得是“芒果数据库”,其实不是的。在英文里,“芒果”是 Mango,而 Mongo 是 humongous 的中间部分,在英文里是“巨大无比”的意思。所以 MongoDB 可以翻译成“巨大无比的数据库”,更优雅的叫法是“海量数据库”。

Viewpoint #

From #

062 | 文档数据库的缔造者MongoDB(上)

影子页表的实现

影子页表的实现 #

我们接下来看下在 KVM 里边影子页表是如何实现的。从影子页表的机制中我们可以看出,实现影子页表的过程中有两个关键点:

  1. cr3 寄存器的切换;
  2. 影子页表的构建。

在第一点中,由于进程切换的时候都需要进行页表的切换,也就是对 cr3 寄存器的修改。因此,当 Guest 在进程切换准备把 Guest 的页表写入 cr3 寄存器时,需要 VMM 介入进来,记录下此时要写入的 Guest 的页表,同时把 GVA 到 HPA 映射的影子页表写入到 cr3 中,完成一次偷梁换柱。

在第二点中,影子页表的构建,主要是通过影子页表的缺页异常处理函数来完成的,它主要的流程是:当 Guest 执行访存指令,来进行访存的时候,会将 GVA 发送给 MMU 进行查找。由于此时 cr3 存放的是影子页表,因此 MMU 会通过影子页表来查找 GVA 对应的 HPA。如果找到了,就可以直接从 HPA 中读取对应的数据,然后流程结束。

如果此时影子页表中还没有 GVA 到 HPA 的映射,就会触发 VM Exit,并从 Guest 模式退出到 Host 模式,由影子页表的缺页处理函数进行处理。影子页表的缺页处理函数会通过上文保存的 Guest 的页表,来查找 GVA 对应的 GPA。

如果 Guest 的页表中,GVA 到 GPA 的映射还不存在,就会由 VMM 向 Guest 注入缺页异常,并交由 Guest 的缺页异常处理函数,完成 GVA 到 GPA 的映射过程。完成映射后,Guest 会继续进行访存,由于此时影子页表中 GVA 到 HPA 的映射还未完成,CPU 此时会继续进入影子页表的缺页异常处理函数中。

...