惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Hacker News
The Hacker News
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
Cisco Talos Blog
Cisco Talos Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Attack and Defense Labs
Attack and Defense Labs
NISL@THU
NISL@THU
L
LINUX DO - 最新话题
PCI Perspectives
PCI Perspectives
Cyberwarzone
Cyberwarzone
K
Kaspersky official blog
V
Vulnerabilities – Threatpost
G
GRAHAM CLULEY
Help Net Security
Help Net Security
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
Security Latest
Security Latest
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Hacker News: Ask HN
Hacker News: Ask HN
C
Cybersecurity and Infrastructure Security Agency CISA
O
OpenAI News
L
LINUX DO - 热门话题
T
Tor Project blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
Security Archives - TechRepublic
Security Archives - TechRepublic
量子位
I
InfoQ
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
SegmentFault 最新的问题
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
雷峰网
雷峰网
Cloudbric
Cloudbric
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
T
Threat Research - Cisco Blogs
Blog — PlanetScale
Blog — PlanetScale
H
Heimdal Security Blog
T
Tenable Blog
Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
美团技术团队
S
Secure Thoughts
Know Your Adversary
Know Your Adversary
H
Hackread – Cybersecurity News, Data Breaches, AI and More

I'm OWenT

国产大模型(GLM 5.1、Kimi K2.6)真实场景效果和 Coding Plan 额度测试 新版本libatapp的连接管理——从etcd服务发现到拓扑驱动的自动重连 新版本libatbus的设计变更——从树形路由到拓扑驱动 Protobuf又一坑 - C++标准和ABI兼容性 AI真好用-给Blog主题统一加mermaid,chart.js,excalidraw,draw.io的多种引入方式支持 给内网部署Squid-通用HTTP下载缓存 UE使用CodeChecker和clang-tidy生成静态分析报告 找出UE的循环依赖 C++小协程栈和临时变量及作用域的栈溢出问题分析 游戏服务的可观测性能力建设(C++生态) 指标上报的多线程优化和多拉取源点优化 协程(libcopp)的Channel功能和CPU命中率优化 通用RPC代码生成器 实现strong_rc_ptr(比shared_ptr更快的引用计数智能指针) 手夯一个STL allocator和对象内存分析组件 std::condition_variable 的信号丢失问题 踩坑一处(GCC)STL std::async 实现BUG导致的crash问题 GCC 14的一个warning to error BUG 给xresloader(Excel导表工具)增强UE读表支持(包含蓝图,Blueprint) Opentelemetry社区在gRPC的几个链接问题(静态库和动态库混用,musl工具链,符号裁剪) Excel转表工具(xresloader)的新验证器(验证外部Excel和文本数据,唯一性和自定义规则) protobuf v22和gRPC v1.55版本升级的依赖变化和upb适配 关于protobuf近期版本(v20/v3.20+)和 gRPC v1.54版本在某些编译环境下的一些链接和编译问题 xresloader-Excel导表工具链的近期变更汇总 打通游戏服务端框架的C++20协程改造的最后一环 Opentelemetry-cpp的Logs模块标准更新(涉及近期版本:1.8-1.9的BREAK CHANGES) 给cmake-toolset和工具链(curl等)加HTTP/2和HTTP/3支持 又开新坑之 coredns 插件: nftables和filter 关于opentelemetry-cpp社区对于C++ Head Only组件单例和符号可见性的讨论小记 填个转表工具 xresloader 去年的坑(数组尾部裁剪) 集成 upb 和 lua binding 的踩坑小记 libcopp对C++20协程的接入和接口设计 再度优化GCC、LLVM、Clang、libc++、libc++abi等套件的构建脚本 游戏服务的分布式事务优化(二)- 事务管理 游戏服务的分布式事务优化(一)- Write Ahead Log(WAL) 模块 记录一些bazel适配用编译选项 测试现代化硬件C++浮点数性能和一致性 适配Boringssl和OpenSSL 3.0 近期cmake-toolset的一些适配问题 C++20 Text Formatting/fmtlib 适配问题小记 再次重构LLVM+Clang+libcxx+libc++abi+其他相关工具的构建流程 重构基于CMake的构建工具链 新版GCC和LLVM+Clang终于Release啦 折腾一下nftables下的双拨 [C++20] Module partitions和符号交叉引用(声明和实现分离) [Rust] 实现一个线程安全且迭代器可以保存的链表 基于protobuf的代码生成 几个使用protobuf中C++接口的Arena的坑 Amazon Aurora DB存储引擎论文阅读小记 近期对libatapp的一些优化调整(增加服务发现和连接管理,支持yaml等) xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等) 在游戏服务器中使用分布式事务 libcopp接入C++20 Coroutine和一些过渡期的设计 libatbus 的大幅优化 nftables初体验 容器配置开发环境小计 PALM Tree - 适合多核并发架构的B+树 - 论文阅读小记 跨平台协程库 - libcopp 简介 C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比) 尝鲜Github Action 一些xresloader(转表工具)的改进 protobuf、flatbuffer、msgpack 针对小数据包的简单对比 协程框架(libcopp) 小幅优化 Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持 C++20 Coroutine libcopp merge boost.context 1.69.0 Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感 Rust玩具-企业微信机器人通用服务 使用ELK辅助监控开发测试环境服务质量和问题定位 2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现 Webpack+vue+boostrap+ejs构建Web版GM工具 Rust的第二次接触-写个小服务器程序 理解和适配AEAD加密套件 atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化 协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比 可执行文件压缩 初识Rust 使用restructedtext编写xresloader文档 atframework的etcd模块化重构 C++的backtrace ECDH椭圆双曲线(比DH快10倍的密钥交换)算法简介和封装 protobuf-net的动态Message实现 pbc的proto3接入 atgateway内置协议流程优化-加密、算法协商和ECDH 整理一波软件源镜像同步工具+DevOps工具 Blog切换到Hugo libcopp v2的第一波优化完成 libcopp(v2) vs goroutine性能测试 libcopp的线程安全、栈池和merge boost.context 1.64.0 GCC 7和LLVM+Clang+libc++abi 4.0的构建脚本 libatbus的几个藏得很深的bug 用cmake交叉编译到iOS和Android 开源项目得一些小维护 atapp的c binding和c#适配 对象路由系统设计 2016年总结 近期的一个协程流程BUG 重写了llvm+clang+libc++和libc++abi的构建脚本 atsf4g完整游戏工程示例|I'm OWenT atframework基本框架已经完成|I'm OWenT
Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记
owent · 2019-04-21 · via I'm OWenT

blog-website

前言

年前被同事安利了这个分布式最终一致性的存储系统 Anna 。初略看了一眼Paper,似乎很是牛X。说是支持任意规模的扩展,并且性能不低于 pedis。于是抽空来看看并了解下这套系统的设计特点和这种夸张的单机性能和扩展性的来源。

主流分布式KVS的比较

系统名词 扩容设计 内存模型 针对单个Key的一致性策略 针对多个Key一致性策略
Masstree 多核 共享内存 线性(Linearizable)
Bw-tree 多核 共享内存 线性(Linearizable)
PALM 多核 共享内存 线性(Linearizable)
MICA 多核 共享内存 线性(Linearizable)
Redis 单核 N/A 线性(Linearizable) 串行化(Serializable)
COPS, Bolt-on 分布式 消息队列 最终一致性(Eventual) 因果一致性(Causal)
Bayou 分布式 消息队列 最终一致性(Eventual), 单调读/写, Read Your Writes 最终一致性(Eventual)
Dynamo 分布式 消息队列 线性(Linearizable), 最终一致性(Eventual)
Cassandra 分布式 消息队列 线性(Linearizable), 最终一致性(Eventual)
PNUTS 分布式 消息队列 线性写, 单调读
CouchDB 分布式 消息队列 最终一致性(Eventual)
Voldemort 分布式 消息队列 线性(Linearizable), 最终一致性(Eventual)
HBase 分布式 消息队列 线性(Linearizable)
Riak 分布式 消息队列 最终一致性(Eventual)
DocumentDB 分布式 消息队列 最终一致性(Eventual), Session, Bounded Staleness, 线性(Linearizable)
Memcached 多核&分布式 共享内存&消息队列 线性(Linearizable)
MongoDB 多核&分布式 共享内存&消息队列 线性(Linearizable)
H-Store 多核&分布式 消息队列 线性(Linearizable) 串行化(Serializable)
ScyllaDB 多核&分布式 消息队列 线性(Linearizable), 最终一致性(Eventual)
Anna 多核&分布式 消息队列 最终一致性(Eventual), 最终一致性(Eventual), Item Cut, Writes Follow Reads, 单调读/写, Read Your Writes, PRAM Read Committed, Read Uncommitted

一致性说明:

  • 线性(Linearizable) 是指在更新了某行之后,后续的客户端不会读到老数据,通常用在单行一致性上,最强的一致性模型;
  • 最终一致性(Eventual) 是指在更新了某行之后,后续的客户端可能在某些(缓存)结点上会读到老数据(特别是并发执行的事务),但是最后(一段时间后)一定会读到一致的最新数据;
  • 串行化(Serializable) 是指对多个读写同一行数据的事务,采用排序和排队执行的机制,这样也能保证数据的严格一致性,但是通常这涉及加锁(spanner/f1)或单点原子化操作(redis);
  • 单调读(Monotonic Reads) 是指在某一个客户端读取到新数据后,不会再读到老数据,但是有可能在更新一行后短期内客户端仍然读到老数据,属于 最终一致性 的一种;
  • 单调写(Monotonic Writes) 是指对单个客户端的写入操作一定是有序的,属于 最终一致性 的一种;
  • 因果一致性(Causal) 是指在某个客户端上对一组Key的读写操作会被认为有因果关系,那么在进程上也都保持一样的可见性顺序,属于 最终一致性 的一种。通常通过 向量时钟(Vector Clock) 实现;
  • Read Your Writes 是指当一个数据行被更新后,这个进程后面的读操作一定会读到这个新值。通常如果数据库系统有 N个副本节点W个节点感知到写入R个节点对读操作返回的数据一致 , 且如果 W + R > N , 那么我们认为当前系统符合 Read Your Writes 一致性,属于 最终一致性 的一种;
  • SessionRead Your Writes的一种更具体的行为,即每一次客户端连接到服务器的Session中保证 Read Your Writes 一致性,如果重新建立Session则不保证,属于 最终一致性 的一种;
  • Bounded Staleness 是指读取操作最多滞后于写入操作最多k个版本或t个周期之后,属于 最终一致性 的一种;
  • Writes follows reads 是指对一个Key的读操作后一定跟着这个Key的写操作;
  • PRAM 是指对于某个进程对多个Key的写入,其他进程看到的写入顺序和这个写入进程的写入顺序一致。因为这些Key在这个写入进程上是同一个pipeline;
  • Read Uncommitted 是指对同一组事务禁止 脏写 ,即多个未提交事务同时修改一组数据;
  • Read Committed 是指事务读取数据时,不允许看到其他未提交事务所写入的数据,通常涉及多个事务并发执行且需要访问同一组数据;

See https://en.wikipedia.org/wiki/Consistency_model for more details

Anna 整体上依赖 bounded join semilattice (文中简称 lattice ) 的核心设计,不知道该怎么翻译了。

数学上 Semilattice 符合 ACI 特性:

  • 交换律(Commutativity): \( \sqcup (a, b) = \sqcup (b, a), \forall_{a,b} \in S \) ,即操作和顺序无关
  • 结合律(Associativity): \( \sqcup (\sqcup (a, b), c) = \sqcup (a, \sqcup (b, c)), \forall_{a,b,c} \in S \) ,即操作和先后次序无关
  • 幂等性(Idempotence): \( \sqcup (a, a) = a, \forall_{a} \in S \) ,即操作多次不影响结果
  • join-semilattice : join操作 \( \sqcup (a, b) \) 指a,b的最小上界。

    这里是数学定义,我的理解在 Anna 中指数据合并操作。

  • bounded : 指存在特定元素 1,使得 \( \sqcup (a, 1) = a , \forall_{a,1} \in S \)

详见维基百科: https://en.wikipedia.org/wiki/Semilattice

我的理解就是一个比较细粒度的模块化数据块,互相之间没有强交互和关联,大多数情况下仅处理自己的数据集。然后对于数据合并的操作,要设计成符合上面的 ACI 特性。

lattice 的基础上,很容易就可以设计出适合这种场景的分布式状态模型和通信模型。

整个架构使用了actor模型。和 seastar 框架相似,系统采用多线程结构,并且按CPU核心数分配线程。并且和 golang 的核心思想一样,用 Message-passingshared-memory 。 这样虽然是多线程,但是每个线程跑自己的 Actor Core ,在业务处理的时候互相之间几乎不需要互相通信。每个actor线程由自己的数据变更集(changeset),然后定期访问广播通道执行集群管理或者是合并操作。

1905-01.png

Anna 的key和节点的分布也是一致性哈希。采用 gossip 算法来处理actor的容灾和扩缩容。按文中的意思似乎数据分片的同步也采用的是 gossip 。不过在这一点上 gossip 对分布式系统的局部分片扩容天生是比 PaxosRaft 要好很多。

另外在 Anna 的actor中,记录了所有其他actor最后感知到这个actor事件的 向量时钟(Vector Clock) ,这样在多副本时,比如出现任意副本对某个Key的删除操作,就可以用因果关系感知到其他副本的actor都同步了这个事件之后再执行真正的垃圾回收操作。这就避免了不一致的时候再被同步回来的问题。这个事件最差情况也会由广播机制定期同步。

其实我有点怀疑这种方案在大规模集群上的延迟,这样意味着每个actor两两之间都需要比较高密度的数据同步。后面给出的各项测试模式里也没有涉及大量节点和大规模跨机器的测试结果。大多数给的都是少数机器几十个节点的性能报告。

弹性可扩展的一致性策略

Anna 是通过设计成一个无需交互,并且让内部符合ACI特性来实现这个高性能高并发的KVS的。Anna 通过一种自底向上的方法,通过把复杂数据结构切割成一个一个的 ACI Building Blocks(Lattice) 来保证整体的保持ACI特性。系统内置了一些一致性模型的设计,然后用户也可以自定义Merge函数。 Anna 的设计重点之一就是方便用户可以用 Anna 已有提供好的符合 ACIlattice 来组合成自己需要的也符合 ACI 的新形态。然后以此来很方便地实现上面提到的那么多种一致性策略。

文中说是以C++模板来实现易扩展的 lattice 的。感觉和STL的思路比较像。

比如说实现了 MapLattice (KV结构) 、 PairLattice (带版本号的数据对) 、 MaxIntLattice (递增整数) 、 ValueLattice (用户自定义数据)。可以按下面的结构实现 因果一致性(Causal)

1905-02.png

如图,使用Key为 ClientID, Value为 MaxIntLatticeMapLattice 来实现因果一致性所需的 向量时钟(Vector Clock) 。 大部分情况下,分片稳定并且系统运行良好的情况下,数据的因果关系可以通过 向量时钟(Vector Clock) 判定出来。少数情况下,如果发生了冲突,就要走冲突合并流程了。只要合并操作符合上面的 ACI 特性,等到一定时间窗以后,无论哪个节点先执行合并、数据合并的顺序是怎样,一定会有一个统一的最终结果。

比如合并数据的时候采用按时间+节点ID排序,然后舍弃老数据。就是无论怎么合并。最终的结果一定是一致的。

再比如 Read Committed 的一致性策略。 其他的部分和 因果一致性(Causal) 一样,只要把维护Key的 向量时钟(Vector Clock) 改成用 MaxIntLattice 表示的最大时间戳,然后合并策略改成按最新时间戳就行了。

性能

Anna 对比其他的 KVS 都是碾压的,但是我个人对其他 KVS的设计不熟,对 redis 倒是比较熟悉。所以这里贴出来它和 redis (主要是 redis-cluster) 的对比。

1905-03.png

如图,在低争用的情况下,Anna 的表现和 redis-cluster 相近。在高争用的时候,这里说是 Anna 的优势比较明显。但是我个人的理解, Anna 的这部分性能完全来自于对一致性的舍弃上。 redis-cluster 是很容易配置成强一致,但是 Anna 是采用了多个 Actor Core 独立运行,然后最终进行Merge的形式。那么在高争用的时候, redis-cluster 相当于收敛到了少数节点上运行,但是仍然是可以实现保证一致性的;而 Anna 是先跑完再Merge,这种的话一致性就比较差,也很难实现CAS类的操作(否则也会fallback到少数节点执行,那么和 Anna 的设计模式就相背离了)。

它在性能消耗分析的部分也说明了,如果一致性策略选的比较弱的话,多副本高争用的情况下还会有Merge开销激增的情况。这个Merge因为是跨节点通信的操作,在Paper提供的3副本的部署结构下大约69%的CPU消耗在这上面。所以影响还是蛮大的,相当于单点性能退化了。

总结

最终一致性和强一致性的数据库系统还是有很大区别,最终一致性不能保证大家看到的中间状态是一致的,并且可能需要自己去选择或者提供冲突时的处理方法。感觉上可能比较适合非关键性数据的分发和存储。至少在游戏项目中,感觉更实用的还是能保证强一致性的系统,即便是NoSQL系统。因为很多东西有比较复杂的逻辑关系,不太能接受多个节点结果不一致的状态。

上面 Anna 和其他系统的比较里也有列出一些强一致性的系统,我觉得和这些强一致的系统比性能其实不太公平。但是 Anna 的一些设计层面的东西还是值得参考的,比如它对worker的设计和考量。这方面它和 pedis 也很像,而且 pedis 性能比它没差太多,但是我的理解没错的话它可以保持强一致,感觉更胜一筹。当然 pedis 功能上目前实现也还是弱了一些,事务的支持和CAS的支持都没有。也就是说乐观锁和悲观锁都还不支持,目前还是没法用于要求强一致的业务里,也就和 Anna 没太大区别了。

从分布式设计来看,Annaredis-cluster 的大体结构是一样的。节点间通信都是消息传递,节点维护都是 gossip ,节点收到其他节点的请求都是redirect过去。区别是 Anna 使用的多线程设计, 而 redis-cluster 是多进程模型;Anna 提供了更完备的proxy层,而redis-cluster目前这方面还得靠客户端支持;然后 Anna 对于resharding的自动化更好一些,并且还实现了热Key的动态副本。如果单单从单点性能的话,Anna 是和redis差不多的。

个人感觉 Anna 最大的优势还是在于它的 lattice 的设计。这极大地方便了对多种一致性策略的扩展。以后如果有什么新的技术方案出来也能够比较容易在这上面实现和测试。