gydtep
发表于 2020-12-13 11:27:27
Intel 早期 cpu(如 Intel386、Intel486、奔腾处理器)实现原子操作,是通过 bus lock 来实现的。这种实现的问题,是完全不相关的两个 cpu 之间,也会相互竞争总线锁,从而导致整体性能下降。
gydtep
发表于 2020-12-13 12:34:23
x86 中,有些指令是自带 lock 语义的,比如 XCHG,更新段描述符等等;另外一些指令可以手动加上 lock 前缀来实现 lock 语义,比如 BTS、BTR、CMPXCHG 指令。
gydtep
发表于 2020-12-13 12:54:10
在这些指令中,最核心的当属 CAS(Compare And Swap)指令了,它是实现各种锁语义的核心指令。不同于自带原子语义的 XCHG,CAS 操作要通过"lock CMPXCHG"这样的形式来实现。一般而言,原子操作的数据长度不会超过 8 个字节,也不允许同时对两个内存地址进行 CAS 操作(如果可以的话,免锁双向链表不是梦)。
gydtep
发表于 2020-12-13 13:07:42
原子操作中另一个绕不开的话题是 ABA 问题,水平有限,就不展开讲了。简单提一个例子,在 linux 内核的 slub 实现中,用上了一个宏 cmpxchg_double,这并不是同时对两个内存地址进行 CAS 的黑魔法,而正是利用 CMPXCHG16B 指令解决 ABA 问题的宏函数,有兴趣的可以深究一把。
gydtep
发表于 2020-12-13 13:40:30
内核中提供了各种各样的锁,自旋锁、读写锁、seq 锁、mutex、semaphore 等等,这些锁对读写者的倾向各有不同,在是否允许睡眠上也有所不同。
gydtep
发表于 2020-12-13 14:23:09
简单来说,自旋锁和读写锁的核心都是利用原子指令来 CAS 操纵一个 32 位/64 位的值,它们都不允许睡眠,但是读写锁对于读者做了优化,允许多个读者同时读取数据,而自旋锁则对于读写操作没有什么偏向性。
gydtep
发表于 2020-12-13 15:03:03
针对大对象原子操作的另一种方式是 COW(copy on write)。
gydtep
发表于 2020-12-13 16:26:18
关于 COW,这里举一个 AEP 的例子。AEP 是一种存储介质,这里只需要知道它可以按字节寻址和数据在掉电后不消失即可。
gydtep
发表于 2020-12-14 10:08:29
consumers 临时节点:记录消费者的清单,主要用于服务治理时查询消费者。
configurations 持久节点:主要保存服务治理时需要调整的服务参数。
routers:子节点为持久节点,主要用于配置服务的动态路由策略。
gydtep
发表于 2020-12-14 10:24:55
随着服务节点的增多,如果客户端都连接选举节点,对选举节点来说需要消耗大量的 CPU 去处理网络连接和请求。但是选举节点又无法任意水平扩容,选举节点越多,事务投票过程就越长,对高并发写性能是不利的。