Blog

海马体是记忆的关键

Content #

海马体是记忆的关键,每天都有新的神经元在海马体中诞生。如果你没有学到任何新东西,这些新生成的神经会有什么变化?如果学到了新东西呢?

如果没有学到东西,新生成的神经元会消失。学到新东西,这些新生成的神经元就会继续存在,在你睡觉时,海马体中的这些新神经元组成的链接就会使唤长时记忆中的链接变得更加强壮。

所有我们需要记住的,都是我们的一个或多个感官传来的信息。这些信息先在我们大脑皮层的不同区域解码,然后大脑海马再将所有的信息整合成一个。海马会将新的信息与先前存储的信息进行比较和关联。该信息如果能通过海马的这道关卡,就会存储到长时记忆中。我们知道,长时记忆中的那些记忆是存储在大脑皮层的不同部分的,但要能够确切说出什么样的信息存储在哪个部分,暂时还缺乏一部分研究。

From #

大脑帝国

由ThreadLocal导致的OOM

Content #

ThreadLocal是 Java 提供的一种保存线程私有信息的机制,因为其在整个线程生命周期内有效,所以可以方便地在一个线程关联的不同业务模块之间传递信息,比如事务 ID、Cookie 等上下文相关信息。ThreadLocal使用不当,很容易造成 OOM。请分析其具体原因。

ThreadLocal数据存储于线程相关的 ThreadLocalMap,其内部条目是弱引用。通常弱引用都会和引用队列配合清理机制使用,但是 ThreadLocal 是个例外,它并没有这么做。

这意味着,废弃项目的回收依赖于显式地触发,否则就要等待线程结束,进而回收相应 ThreadLocalMap!这就是很多 OOM 的来源,所以通常都会建议,应用一定要自己负责 remove,并且不要和线程池配合,因为 worker 线程往往是不会退出的。

From #

两种睡眠状态

Content #

在 Linux 中,进程有哪两种睡眠状态?两者有何区别?

  1. TASK_INTERRUPTIBLE 可中断的睡眠状态。这是一种浅睡眠的状态,也就是说,虽然在睡眠,等待 I/O 完成,但是这个时候一个信号来的时候,进程还是要被唤醒。只不过唤醒后,不是继续刚才的操作,而是进行信号处理。当然程序员可以根据自己的意愿,来写信号处理函数,例如收到某些信号,就放弃等待这个 I/O 操作完成,直接退出;或者收到某些信息,继续等待。
  2. TASK_UNINTERRUPTIBLE 不可中断的睡眠状态。这是一种深度睡眠状态,不可被信号唤醒,只能死等 I/O 操作完成。一旦 I/O 操作因为特殊原因不能完成,这个时候,谁也叫不醒这个进程了。你可能会说,我 kill 它呢?别忘了,kill 本身也是一个信号,既然这个状态不可被信号唤醒,kill 信号也被忽略了。除非重启电脑,没有其他办法。

From #

二阶段提交协议的四个缺点

Content #

二阶段提交协议的缺点:同步阻塞、单点问题、脑裂、太过保守。这些缺点的含义分别是什么?

同步阻塞 #

二阶段提交协议存在的最明显也是最大的一个问题就是同步阻塞,这会极大地限制分布式系统的性能。在二阶段提交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,也就是说,各个参与者在等待其他参与者响应的过程中,将无法进行其他任何操作。

单点问题 #

协调者的角色在整个二阶段提交协议中起到了非常重要的作用。一旦协调者出现问题,那么整个二阶段提交流程将无法运转,更为严重的是,如果协调者是在阶段二中出现问题的话,那么其他参与者将会一直处于锁定事务资源的状态中,而无法继续完成事务操作。

数据不一致 #

在二阶段提交协议的阶段二,即执行事务提交的时候,当协调者向所有的参与者发送Commit请求之后,发生了局部网络异常或者是协调者在尚未发送完Commit请求之前自身发生了崩溃,导致最终只有部分参与者收到了Commit请求。于是,这部分收到了Commit请求的参与者就会进行事务的提交,而其他没有收到Commit请求的参与者则无法进行事务提交,于是整个分布式系统便出现了数据不一致性现象。

太过保守 #

如果在协调者指示参与者进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应信息的话,这时协调者只能依靠其自身的超时机制来判断是否需要中断事务,这样的策略显得比较保守。换句话说,二阶段提交协议没有设计较为完善的容错机制,任意一个节点的失败都会导致整个事务的失败。

From #

付出者更容易开启休眠的关系

Content #

休眠的关系是我们关系网络中被忽略的价值,而付出者与获取者、互利者相比,拥有独到的优势,更容易开启这些价值。为什么?

对于获取者来说,重新激活休眠的关系是一种挑战。如果休眠的关系对象也是获取者,他们会生疑而且自我防范,不愿意给出新异的信息;如果休眠的关系对象是互利者,他们则可能希望惩罚获取者,就像我们在“最后通牒”游戏中看到的那样;如果休眠的关系对象是聪明的付出者,之后我们也将谈到,他们不会那么愿意帮助获取者。当然,如果获取者的自利行为就是导致一段关系休眠的原因,那么重新激活这段关系就根本不可能了。

互利者想要重新建立联系会容易得多,但是他们经常不习惯于向别人寻求帮助,因为他们执着于互惠的规则。如果找别人帮忙,他们会感觉自己欠了别人的,需要回报。如果他们在休眠的关系中已经有所亏欠,还没有做出补偿,那么再寻求帮助就更难了。而且,对于许多互利者来说,休眠的关系并没有建立起足够深入的信任,因为他们更愿意和别人交易,而非建立有意义的关系。

From #

limits与requests的区别

Content #

Kubernetes 里 Pod 的 CPU 和内存资源,实际上还要分为 limits 和 requests 两种情况,两者有何区别?

在调度的时候,kube-scheduler 只会按照 requests 的值进行计算。而在真正设置 Cgroups 限制的时候,kubelet 则会按照 limits 的值来进行设置。

From #

强引用、软引用、弱引用和虚引用

Content #

在JDK 1.2版之后,Java对引用的概念进行了扩充,将引用分为强引用(Strongly Re-ference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。这四种引用类型的含义分别是什么?

强引用是最传统的“引用”的定义,是指在程序代码之中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。

软引用是用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2版之后提供了SoftReference类来实现软引用。

弱引用也是用来描述那些非必须对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2版之后提供了WeakReference类来实现弱引用。

虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2版之后提供了 PhantomReference类来实现虚引用。

From #

数据一致性与事务一致性

Content #

数据一致性关注的是单对象、单操作在多副本上的一致性,事务一致性则是关注多对象、多操作在单副本上的一致性,分布式数据库的一致性是数据一致性与事务一致性的融合。

From #

toc:Database

架构 #

数据库的基本架构 分布式数据库架构风格 单体数据库架构风格的演进 NewSQL架构 双向同步模式 计算下推 TiDB的计算下推 OLAP和OLTP通过ETL来衔接 Kappa架构 解决OLAP系统数据时效性问题的两种思路 NSM(行式存储) DSM(列式存储) 融合性存储PAX(Partition Attributes Across) TiFlash存储分离

Content #

自增主键无法连续递增 自增主键无法单调递增 雪花算法(Snowflake) RUM猜想 B+Tree的写放大与存储不连续 LSM-Tree数据落盘过程 Size-Tiered Compact Strategy Leveled Compact Strategy

远端写入时间戳异常 数据库的三级模式

查询 #

嵌套循环连接算法 Simple Nested Loop Join Block Nested-Loop Join Index Lookup Join 排序归并连接算法 Simple Hash Join Grace Hash Join

分布式数据库 #

分布式数据中的大小表关联(复制表) 分布式数据库中的大表关联(重分布)

事务 #

幻读与不可重复读的区别 2PC的三大问题 隔离级别与视图创建时间 悲观协议与乐观协议 并发控制的三个阶段 乐观协议的挑战 串行化图(Serializable Graph,SG) 串行化图构建实例 分布式2PC事务延迟估算 缓存写提交(Buffering Writes until Commit) 缓存写提交存的两个缺点

基于日志的延迟修改技术(deferred-modification technique)

索引 #

分区索引 HBase的分区索引

备份 #

RPO(Recovery Point Objective) 两地三中心五副本

Consistency Models A Critique of ANSI SQL Isolation Levels Bigtable: A Distributed Storage System for Structured Data Spanner: Google’s Globally-Distributed Database Consistent Hashing and Random Trees Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases Large-scale Incremental Processing Using Distributed Transactions and Notifications On Optimistic Methods for Concurrency Control

...

幻读与不可重复读的区别

Content #

Critique 对幻读的描述大致是这样的,事务 T1 使用特定的查询条件获得一个结果集,事务 T2 插入新的数据,并且这些数据符合 T1 刚刚执行的查询条件。 T2 提交成功后,T1 再次执行同样的查询,此时得到的结果集会增大。这种异常现象就是幻读。

不少人会将幻读与不可重复读混淆,这是因为它们在自然语义上非常接近,都是在一个事务内用相同的条件查询两次,但两次的结果不一样。差异在于,对不可重复读来说,第二次的结果集相对第一次,有些记录被修改(Update)或删除(Delete)了;而幻读是第二次结果集里出现了第一次结果集没有的记录 (Insert)。一个更加形象的说法,幻读是在第一次结果集的记录“间隙”中增加了新的记录。所以,MySQL 将防止出现幻读的锁命名为间隙锁(Gap Lock)。

Viewpoints #

From #

03|强一致性:别再用BASE做借口,来看看什么是真正的事务一致性