OWenT's blog
  • Introduction
  • About Me
  • 2020
    • 近期对libatapp的一些优化调整(增加服务发现和连接管理,支持yaml等)
    • xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等)
    • 在游戏服务器中使用分布式事务
    • libcopp接入C++20 Coroutine和一些过渡期的设计
    • libatbus 的大幅优化
    • nftables初体验
    • 容器配置开发环境小计
  • 2019
    • PALM Tree - 适合多核并发架构的B+树 - 论文阅读小记
    • 跨平台协程库 - libcopp 简介
    • C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比)
    • 尝鲜Github Action
    • 一些xresloader(转表工具)的改进
    • protobuf、flatbuffer、msgpack 针对小数据包的简单对比
    • 协程框架(libcopp) 小幅优化
    • Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持
    • Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记
    • C++20 Coroutine
    • libcopp merge boost.context 1.69.0
    • Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感
    • Rust玩具-企业微信机器人通用服务
  • 2018
    • 使用ELK辅助监控开发测试环境服务质量和问题定位
    • Webpack+vue+boostrap+ejs构建Web版GM工具
    • 2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现
    • Rust的第二次接触-写个小服务器程序
    • 理解和适配AEAD加密套件
    • atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化
    • 协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比
    • 可执行文件压缩
    • 初识Rust
    • 使用restructedtext编写xresloader文档
    • atframework的etcd模块化重构
    • C++的backtrace
  • 2017
    • 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
  • 2016
    • 重写了llvm+clang+libc++和libc++abi的构建脚本
    • atsf4g完整游戏工程示例
    • atframework基本框架已经完成
    • 游戏服务器的不停服更新
    • 对atbus的小数据包的优化
    • Android和IOS的TLS问题
    • pbc的一个陈年老BUG
    • boost.context-1.61版本的设计模型变化
    • 接入letsencrypt+全面启用HTTP/2
    • 理解Raft算法
    • libatbus基本功能及单元测试终于写完啦
    • 博客文章和文档迁移到gitbook
  • 2015
    • 博客文章和文档迁移到gitbook
    • 给客户端写得LRU缓存
    • 近期活动比较零散
    • 关于BUS通信系统的一些思考(三)
    • 针对Java JIT的优化(转表工具:xresloader)
    • libcopp更新 (merge boost 1.59 context)
    • 小记最近踩得两个C++坑
    • Redis全异步(HA)Driver设计稿
    • Vim常用命令
    • 关于firewalld和systemd的一些命令速记
    • Jenkins(hudson)插件记录
    • 我们的Lua类绑定机制
    • LLVM+Clang+Libcxx+Libcxxabi(3.6)工具链编译(完成自举编译)
    • 回顾2014
    • Android NDK undefined reference to ___tls_get_addr 错误
    • gitlab腾讯企业邮箱配置
  • 2014
    • 回顾2013
    • C++11动态模板参数和type_traits
    • C++又一坑:动态链接库中的全局变量
    • tolua++内存释放坑
    • [转]类似github的框架
    • Lua性能分析
    • 集成Qt Webkit 到cocos2d-x
    • Gitlab环境搭建小计
    • 近期研究VPN的一些记录(OpenVPN,pptp,l2tp)
    • LLVM + Clang + Libcxx + Libcxxabi 工具链编译
    • 关于BUS通信系统的一些思考(二)
    • 关于BUS通信系统的一些思考(一)
    • [libiniloader] Project
    • 记录一些在线编辑器
    • [WP Code Highlight.js] Project
    • 再议 C++ 11 Lambda表达式
    • 基于Chrome插件的开发工具链
    • [ACM] HDU 1006 解题报告
    • Linux 编译安装 GCC 4.9
    • 又碰到了这个解谜游戏,顺带记下地址
    • 简单C++单元测试框架(支持一键切到GTest或Boost.Test)
    • 捣鼓一个协程库
  • 2013
    • std和boost的function与bind实现剖析
    • 不知道是哪一年的腾讯马拉松题目 照片评级 解题报告
    • Lua 挺好用的样子
    • VC和GCC成员函数指针实现的研究(三)
    • VC和GCC成员函数指针实现的研究(二)
    • VC和GCC内成员函数指针实现的研究(一)
    • 一个C++关于成员变量偏移地址的小Trick
    • ptmalloc,tcmalloc和jemalloc内存分配策略研究
    • POJ 2192 Zipper HDU 2059 龟兔赛跑
    • 从Javascript到Typescript到Node.js
    • 网络编程小结
    • 试试Boost.Asio
    • Lnmp yum 安装脚本 (for CentOS)
    • ARM 交叉编译环境搭建
    • Linux 编译安装 GCC 4.8
    • [记录]虚拟硬盘的压缩|磁盘写零
  • 2012
    • Boost.Spirit 初体验
    • “C++的90个坑”-阅读笔记
    • AC自动机
    • C++ 标准过渡期
    • 程序员修炼之道 -- 阅读笔记
    • [转载]狼与哈士奇
    • C++ 新特性学习(八) — 原子操作和多线程库[多工内存模型]
    • C++ 新特性学习(七) — 右值引用
    • 理解Protobuf的数据编码规则
    • 忆往昔ECUST的ACM时代
    • Linux编译安装GCC 4.7
    • JSON显示库 -- showJson (Javascript)
    • C++ 新特性学习(六) — 新的字符串编码和伪随机数
    • C++ 新特性学习(五) — 引用包装、元编程的类型属性和计算函数对象返回类型
    • C++ 新特性学习(四) — Bind和Function
  • 2011
    • C++ 新特性学习(三) — Regex库
    • C++ 新特性学习(二) -- Array、Tuple和Hash库
    • C++ 新特性学习(一) -- 概述+智能指针(smart_ptr)
    • Linux 和 Windows PowerShell 常用工具/命令 记录
    • 非常帅气的Linq to sql
    • 2011 Google Code Jam 小记
    • C++总是很神奇
    • 大学生创新项目[国家级]经费使用记录
    • 常用官方文档整理
    • 我们学校的IPV6很不错嘛
  • 2010
    • 线段树相关问题 (引用 PKU POJ题目) 整理
    • 2010 ACM 赛前笔记
    • POJ PKU 2596 Dice Stacking 解题报告
    • POJ PKU 3631 Cuckoo Hashing 解题报告
    • POJ PKU 1065 Wooden Sticks 3636 Nested Dolls 解题报告
    • HDU 3336 Count the string 解题报告
    • Hash模板 个人模板
    • ZOJ 3309 Search New Posts 解题报告
    • POJ PKU Let's Go to the Movies 解题报告
    • 注册表常用键值意义
    • PKU POJ 1724 ROADS 解题报告
    • 《神奇古今秘方集锦》&《民间秘术大全》
    • PKU POJ 1720 SQUARES 解题报告
    • POJ PKU 2155 Matrix 解题报告
    • PKU POJ 1141 Brackets Sequence 解题报告
    • PKU POJ 2728 Desert King 解题报告
    • PKU POJ 2976 Dropping tests 解题报告
    • PKU POJ 3757 Simple Distributed storage system 解题报告
    • GCD Determinant 解题报告
    • Southeastern European 2008 Sky Code 解题报告
    • HDU HDOJ 3400 Line belt 解题报告
    • 线性筛法求质数(素数)表 及其原理
    • HDU HDOJ 3398 String 解题报告
    • 树状数组模块(个人模板)
    • 浙江理工 省赛总结 team62 By OWenT of Coeus
    • POJ PKU 3659 Cell Phone Network 解题报告
    • USACO 2008 March Gold Cow Jogging 解题报告
    • C#格式化输出(记录)
    • 参加有道难题笔记
    • POJ PKU 2446 Chessboard 解题报告
    • POJ PKU 1986 Distance Queries 解题报告
    • 计算几何算法概览[转载]
    • 关于差分约束(转载)
    • POJ PKU 2826 An Easy Problem?! 解题报告
    • 数论模板(个人模板)
    • 简易四则运算(ACM个人模板)
    • Catalan 数
    • The 35th ACM/ICPC Asia Regional Tianjin Site —— Online Contest 1009 Convex 解题报告
    • JQuery扩展插件--提示信息
    • ACM 计算几何 个人模板
    • 解析网站字符串型参数 Javascript QueryString 操作 TQueryString类
    • POJ PKU 1474 Video Surveillance 解题报告
  • 2009
    • 模式匹配(kmp)个人模板
    • 并查集 模板
    • POJ 3267 The Cow Lexicon 解题报告
    • C/C++语言常用排序算法
    • POJ 2606 Rabbit hunt 2780 Linearity 1118 Lining Up 解题报告
    • 打造最快的Hash表(转) [以暴雪的游戏的Hash为例]
    • ECUST 09年 校赛个人赛第六,七场总结
    • ECUST 09年 校赛个人赛第三场部分解题报告(A,D,F,I)
    • 牛顿迭代解方程 ax^3+bX^2+cx+d=0
    • 09年8月9日 ECUST ACM 练习赛总结
    • 连接最多点直线 (OWenT 个人模板)
    • 点到直线距离 和 线段间最短距离 (OWenT 模板)
    • ECUST 09年 校赛个人训练赛第五场总结
    • ECUST 09年 校赛个人赛第八场(最后一场)总结
    • 09年8月14日 ECUST ACM 练习赛总结
    • 矩阵相关 (增强中)
    • Prime最小生成树(个人模板)
    • 最长单调子序列 复杂度nlog(n)
    • POJ PKU 2549 Sumsets 解题报告
    • POJ PKU 3277 City Horizon 解题报告
    • 我的ACM生涯
    • POJ PKU 2528 Mayor's posters 解题报告
    • POJ PKU 2378 Tree Cutting 解题报告
    • POJ PKU 1990 MooFest 解题报告
Powered by GitBook
On this page
  • 前言
  • 主流分布式KVS的比较
  • Anna 架构设计
  • 弹性可扩展的一致性策略
  • 性能
  • 总结

Was this helpful?

  1. 2019

Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记

PreviousExcel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持NextC++20 Coroutine

Last updated 6 years ago

Was this helpful?

前言

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

主流分布式KVS的比较

系统名词

扩容设计

内存模型

针对单个Key的一致性策略

针对多个Key一致性策略

Masstree

多核

共享内存

无

Bw-tree

多核

共享内存

无

PALM

多核

共享内存

无

MICA

多核

共享内存

无

Redis

单核

N/A

COPS, Bolt-on

分布式

消息队列

Bayou

分布式

消息队列

Dynamo

分布式

消息队列

无

Cassandra

分布式

消息队列

无

PNUTS

分布式

消息队列

线性写, 单调读

无

CouchDB

分布式

消息队列

无

Voldemort

分布式

消息队列

无

HBase

分布式

消息队列

无

Riak

分布式

消息队列

无

DocumentDB

分布式

消息队列

无

Memcached

多核&分布式

共享内存&消息队列

无

MongoDB

多核&分布式

共享内存&消息队列

无

H-Store

多核&分布式

消息队列

ScyllaDB

多核&分布式

消息队列

无

Anna

多核&分布式

消息队列

一致性说明:

  • Writes follows reads 是指对一个Key的读操作后一定跟着这个Key的写操作;

  • 交换律(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的最小上界。

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

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

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

弹性可扩展的一致性策略

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

性能

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

总结

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

, 单调读/写,

,

,

,

, , ,

,

, , Item Cut, Writes Follow Reads, 单调读/写, ,

,

是指在更新了某行之后,后续的客户端不会读到老数据,通常用在单行一致性上,最强的一致性模型;

是指在更新了某行之后,后续的客户端可能在某些(缓存)结点上会读到老数据(特别是并发执行的事务),但是最后(一段时间后)一定会读到一致的最新数据;

是指对多个读写同一行数据的事务,采用排序和排队执行的机制,这样也能保证数据的严格一致性,但是通常这涉及加锁([spanner][22]/)或单点原子化操作();

单调读(Monotonic Reads) 是指在某一个客户端读取到新数据后,不会再读到老数据,但是有可能在更新一行后短期内客户端仍然读到老数据,属于 的一种;

单调写(Monotonic Writes) 是指对单个客户端的写入操作一定是有序的,属于 的一种;

是指在某个客户端上对一组Key的读写操作会被认为有因果关系,那么在进程上也都保持一样的可见性顺序,属于 的一种。通常通过 实现;

是指当一个数据行被更新后,这个进程后面的读操作一定会读到这个新值。通常如果数据库系统有 N个副本节点 , W个节点感知到写入 , R个节点对读操作返回的数据一致 , 且如果 W + R > N , 那么我们认为当前系统符合 一致性,属于 的一种;

是的一种更具体的行为,即每一次客户端连接到服务器的Session中保证 一致性,如果重新建立Session则不保证,属于 的一种;

是指读取操作最多滞后于写入操作最多k个版本或t个周期之后,属于 的一种;

是指对于某个进程对多个Key的写入,其他进程看到的写入顺序和这个写入进程的写入顺序一致。因为这些Key在这个写入进程上是同一个pipeline;

是指对同一组事务禁止 脏写 ,即多个未提交事务同时修改一组数据;

是指事务读取数据时,不允许看到其他未提交事务所写入的数据,通常涉及多个事务并发执行且需要访问同一组数据;

See for more details

架构设计

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

数学上 符合 ACI 特性:

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

详见维基百科:

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

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

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

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

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

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

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

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

再比如 的一致性策略。 其他的部分和 一样,只要把维护Key的 改成用 MaxIntLattice 表示的最大时间戳,然后合并策略改成按最新时间戳就行了。

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

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

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

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

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

[22]: "Spanner: Google's Globally-Distributed Database"

Anna
pedis
线性(Linearizable)
最终一致性(Eventual)
串行化(Serializable)
f1
redis
最终一致性
最终一致性
因果一致性(Causal)
最终一致性
向量时钟(Vector Clock)
Read Your Writes
Read Your Writes
最终一致性
Session
Read Your Writes
Read Your Writes
最终一致性
Bounded Staleness
最终一致性
PRAM
Read Uncommitted
Read Committed
https://en.wikipedia.org/wiki/Consistency_model
Anna
Anna
bounded join semilattice
lattice
Semilattice
Anna
https://en.wikipedia.org/wiki/Semilattice
lattice
seastar
Anna
gossip
gossip
gossip
Paxos
Raft
Anna
向量时钟(Vector Clock)
Anna
Anna
ACI Building Blocks(Lattice)
Anna
Anna
lattice
lattice
因果一致性(Causal)
向量时钟(Vector Clock)
向量时钟(Vector Clock)
Read Committed
因果一致性(Causal)
向量时钟(Vector Clock)
Anna
redis
redis
Anna
redis-cluster
Anna
Anna
redis-cluster
Anna
redis-cluster
Anna
Anna
Anna
Anna
pedis
pedis
pedis
Anna
Anna
redis-cluster
gossip
Anna
redis-cluster
Anna
Anna
Anna
Anna
lattice
https://ai.google/research/pubs/pub39966
线性(Linearizable)
线性(Linearizable)
线性(Linearizable)
线性(Linearizable)
线性(Linearizable)
串行化(Serializable)
最终一致性(Eventual)
因果一致性(Causal)
最终一致性(Eventual)
Read Your Writes
最终一致性(Eventual)
线性(Linearizable)
最终一致性(Eventual)
线性(Linearizable)
最终一致性(Eventual)
最终一致性(Eventual)
线性(Linearizable)
最终一致性(Eventual)
线性(Linearizable)
最终一致性(Eventual)
最终一致性(Eventual)
Session
Bounded Staleness
线性(Linearizable)
线性(Linearizable)
线性(Linearizable)
线性(Linearizable)
串行化(Serializable)
线性(Linearizable)
最终一致性(Eventual)
最终一致性(Eventual)
最终一致性(Eventual)
Read Your Writes
PRAM
Read Committed
Read Uncommitted
1905-01.png
1905-02.png
1905-03.png