跨平台协程库 - libcopp 简介
前段时间有同事联系我想看看可能推广我之前写的协程库 libcopp,虽然 libcopp 已经用到过好几个项目上,这几年也断断续续地写了一些实现细节的文章,但是也但确实需要系统、概览性地介绍下 libcopp ,所以就有了这篇文章。
Github: https://github.com/owent/libcopp Document: https://libcopp.atframe.work/
libcopp 的由来
协程的概念并不是什么非常新颖的东西,最早有做 libcopp 的想法的时候,是听了微信分享的 libco 。但是我们游戏业务里大部分的实现都还是走的事务和Task/Step的模型,特别是C++上异步调用非常不直观。而这种协程的方法可以比较容易地把接口设计得很简洁,而且后续的功能集成上也很容易不破坏原有的API约定,还有微信这么大的业务背书,我们就想在游戏业务里也使用这种方案。我们先是预研了一些类似的方案,但是都不是特别满意。
C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比)
前言
之前写了 《协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比》 和 《C++20 Coroutine》 ,但是一直没写 C++20 Coroutine 的测试报告。
现在的草案版本比我当时写 《C++20 Coroutine》 的时候有了一点点更新,cppreference 上有文档了(https://en.cppreference.com/w/cpp/language/coroutines) 。里面列举的标准文档是P0912R5,这个文档目前还没完工,详情可以看他的来源N4775。不过内容上暂时还没有太大的变化,今天我就照着之前的方式来benchmark一波 C++20 Coroutine 吧。
压力测试机环境
为了方便比较,我更新了一下之前在 《协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比》 里的测试项目的版本。Windows环境仅仅是为了测试MSVC下的性能,因为GCC还不支持所以Linux下是使用Clang编译的。
尝鲜Github Action
前言
Github Action 上线有一阵子了,大概两周前我的所有账号也是都陆陆续续开发了beta测试的权限。然后就来研究了下这个新的 CI 系统是怎么回事。看介绍,和之前碰到的一些CI系统不太一样的地方是,Github是做了一个商店的功能。这样大家就可以自己定义自己的Action,然后方便别人复用。同时也可以统一自己的或者组织在构建过程中的一些公共流程。
目前 Github Action 的文档还是不是特别的齐全,有些东西找起来比较费劲,还要参考下别人写的成品来理解。我是先试着用 Github Action 来发布我的blog,然后想给 xresloader 的自动发布也改成 Github Action ,但是找了一圈发现没有合适的已有的Action,就自己写了一个。功能类似 travis-ci 的 Github Release Deployment,发布到了商店: https://github.com/marketplace/actions/uploadtogithubrelease
一些xresloader(转表工具)的改进
前言
最近有几个其他项目组的童鞋给我之前的 转表工具链-xresloader 提了几个需求。然后我也根据我们近期一些需求点对转表工具链一起给这套工具做了点功能增强和细节上的一些改进。 这篇blog差不多是这些东西的 CHANGELOG了吧。
插件和协议和CI
对一些复杂的需求,使用protobuf插件机制比配置在excel里描述能力要强的多。所以近期大多的新功能都是由插件配置的。但是以前 转表引擎-xresloader 的发布流程里只包含输出的jar,协议得去对应源码包里找。另外一个童鞋报给我说找 github 的release里的源码包似乎并不支持git lfs,解出来的git lfs文件只有一个版本号,所以我给CI的发布流程里加了对应版本的protocol文件的打包,当然也包括插件的protocol。
protobuf、flatbuffer、msgpack 针对小数据包的简单对比
前言
前段时间我尝试给 atframework 的 libatapp 整合进UnrealEngine做Dedicated Server和逻辑server通信的时候碰到了一些问题。主要在于这些客户端引擎一般来说默认都是关闭exception的甚至会关闭RTTI。而 libatapp 所依赖的通信组件 libatbus 里内部协议是msgpack , 而 msgpack 的官方 C++ 的header only的实现是必须开异常的功能的。所以我近期打算抽空增强一波 libatbus 的功能,增加一些跨版本向前向后兼容功能,和一些简单的验证功能(仅仅是为了防止误操作导致的问题)。具体的变更等我弄完了再发一篇。
协程框架(libcopp) 小幅优化
最近抽空继续对 libcopp 进行了更新和小幅优化。 首先的Merge了 boost.context 1.70.0 。这次boost.context的更新似乎和它写进 CHANGELOG 里的并不完全一致,匹配的只看到 macho 架构的脏数据操作。 不过另外它增加了新的平台支持 mips64,我目前还是简单导入了,但是平台检测工具还没有写,如果要使用是可以通过编译参数切过去的,不过我感觉没人会这么用吧?我自己用都得看一下之前怎么写的。
Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持
前言
我们项目组最近在学习UE,然后就涉及导表这个东东。之前我已经做过一个功能比较全面并且跨平台的Excel导出protobuf、msgpack、xml、lua、json、javascript等的工具 xresloader 。并且做了方便服务器集成的CLI工具和方便策划、前端用的GUI工具。那么这次很自然地就让它能够导出UE所支持的内容就行了。然后额外增加了基于protobuf插件形式的多key索引和自动生成一些支持蓝图和非蓝图的常用接口代码。
Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记
前言
年前被同事安利了这个分布式最终一致性的存储系统 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 |
一致性说明:
C++20 Coroutine
前言
最近的新闻里 C++20 已经确认的内容里已经有了协程组件,之前都是粗略看过这个协程草案。最近抽时间更加系统性的看了下接入和实现细节。
我的测试代码都是在MSVC下开启 /await 选项后测试的,在我本地的Linux clang环境中,可以通过 $LLVM_CLANG_PREFIX/bin/clang++ -std=c++2a -O0 -g -ggdb -stdlib=libc++ -fcoroutines-ts -lc++ -lc++abi -Wl,-rpath=$LLVM_CLANG_PREFIX/lib/ test.cpp 编译和运行。
libcopp merge boost.context 1.69.0
过年啦,最近在看一些非技术性的东西,Anna 的Paper也还没看完。随手优化了下Blog的主题,修复和优化了一些小问题。然后来Merge了一下 boost.context 最新 1.69.0 版本的asm部分到 libcopp。
其实我有一直跟进 boost.context 的版本发布,但是现在的版本已经少有BUG了,最近的几次 boost 的 release对于 boost.context 的变化很少,而且我集成的部分也基本上没涉及到,所以最近的两个版本都没有急着Merge。 1.68.0 版本的变化是修复使用 context-impl=ucontext 时,链接报重定义的问题。但是我在 libcopp 里仅使用了它上下文切换的部分和栈与上下文结构,没有使用它的协程对象的部分(主要是觉得它的实现不好用,而且有一些历史遗留包袱)。所以这个对 libcopp 来说相当于没有变化。而在 1.69.0 里主要也是一些环境的编译问题和 boost 构建工具和Jamfile.v2方面的优化。不过有一项是和 libcopp 有一些关系的,那就是为ELF的ABI添加了 .file 段。按照PR提交者的说法是如果不添加这个, 链接器会自动添加一个编译时的绝对地址(详情见: https://github.com/boostorg/context/issues/91 )。这个也是辅助性质的,不属于实际功能的改动。
Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感
前言
之前看过 《大规模分布式存储系统:原理解析与架构实战》 ,这个系统设计还是挺有意思的,里面提及了Google的一整套系统都有论文,而且现在已经进化到下一代支持分布式跨行事务的关系型数据库系统了。所以一直很想抽时间看看Google的那套去中心化并且可以平行扩容的分布式系统和数据库的论文。之前一些计划中的我自己的项目的优化项都差不多完成了,这段时间就陆陆续续的看完了这三篇Paper,可怜我的渣渣英语,所以看得比较慢。
Rust玩具-企业微信机器人通用服务
使用ELK辅助监控开发测试环境服务质量和问题定位
什么是ELK?
ELK 是 elasticsearch + logstash + kibana的缩写。这一套是现在比较流行的日志全文索引系统了。我之前的项目也有用它来做过日志分析,这次主要是拿来搭建开发测试环境的监控和分析系统,顺带记录一下部署脚本和流程。
其中 elasticsearch 是日志索引系统,我按两个master,3个数据和处理节点来部署。 logstash 和 kibana 因为是开发测试环境使用,量级不大,所以只部署了一个节点。但是在使用过程中发现 elasticsearch 在jre的GC的时候还是有较长时间的 Stop The World 的问题,而且这期间的数据会倍丢弃。所以为了缓解这个状况,又引入了 redis 作为消息队列使用。然后使用两组pipeline,一个从 client -> logstash -> redis ,另一个从 redis -> logstash -> elasticsearch 来传输。这样如果在 elasticsearch GC的 Stop The World 结束的时候会把数据补回去。 外面更大型的部署也有用 kafka 或者更进一步优化的 pulsar。不过我们目前的应用也不太需要 kafka 和 pulsar 那种数据落地和强一致性,使用 redis 也已经够了。
2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现
前段时间看到说Lua 5.4用了一种新的通用随机数算法,替换掉本来内部使用的CRT的随机数引擎。我看了一下大致的实现,CPU和空间复杂度任然保持了一个较低的水平,并且循环节和说是随机性都还不错。我们游戏项目中原本对大量随机数场景的随机数算法使用的是基于线性同余的TAUS88,但是使用过程中发现这个算法分布上还是有一些不是很理想,所以就想把这个新的科研成果也用进我们项目中试试看效果。
Webpack+vue+boostrap+ejs构建Web版GM工具
前言
Web前端的组件技术刷新真的是日新月异,前段时间看到很多童鞋分享了webpack的使用,刚好之前做我们游戏里Web版的GM工具的时候正在想怎么用简单的方式,做模块分离并且又不需要引入重量级的第三方库或组件,也不需要太繁琐的流程(毕竟只是个小工具)。
我们的Web版GM工具长差不多这个样子,全静态页面。


因为分成了好几个模块,然后由于用的是bootstrap的。上面的Tab和下面的内容还有处理逻辑的函数都分了三大块,在不同的位置。在内容持续增加以后,全都写在一个html里太不方便了,而如果走ajax加载,调试和本地编辑都挺麻烦。
Rust的第二次接触-写个小服务器程序
JUST PRACTICE
蛮久前入门了一下 Rust 语言。它的设计模型非常地吸引C/C++的开发者。但是学习语言嘛还是要练习一下,之前也用它给我们项目写了个命令行小工具。这回拿来写个小型的服务器程序吧。
Rust 的生态还处于非常初级的阶段。很多组件和库都处于开发中和设计变更的阶段,比起golang来,很多功能库都没有。 服务器编程本身特别注重高并发能力和,高性能。和原来很多客户端程序的思路是不太一样的。所以本来想等新的Futures和await和2.0版本的宏机制完成再搞。而老的Futures库由于即将移入核心库,在crates.io上下架了。现在似乎很多Rust的库都按Tokio的的模式来,于是我看了一下基于Futures的多路复用IO库Tokio的文档来练习一下这个小服务器程序。
理解和适配AEAD加密套件
什么是AEAD
按照维基百科的说法。AEAD的全称是Authenticated encryption (AE) and authenticated encryption with associated data (AEAD, variant of AE)。也就是带附加数据的加密和验证算法。
我们很多涉及IO的系统收发数据的时候一般会加上一些校验码,以便检测IO错误。而对外的socket里,这个校验码还有一个功能是挡掉一些不正常的数据。如果这时候如果我们的数据需要带上加密的话,那就是AE了。然后AEAD就是在AE的基础上,增加一些自定义数据,用于防止猜解。
atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化
前言
年前就计划把以前项目的一些理念和设计方案融合到sample里来。但是内容比较多,一直也没太多时间去完成它。所幸虽然断断续续但终归是完成了。并且在之前的一些实现上还做了一些细节的优化。内容比较多我感觉我自己写的也比较乱,仅当作一个参照和小计吧。
协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比
协程系统优化
libcopp很早就实现完成了v2版本,现在迁移进atsf4g-co/tree/sample_solution以后也把v2分支正式并入了主干。原来的版本切出到v1分支并且停止维护了。
libcopp v2内存布局
开发libcopp v2版本的最大目的是优化allocator的接口和内存碎片。
原来的allocator虽然是可定制的,但是是内置的。每次创建一个allocator对象,不同allocator之间共享数据只能通过全局数据或者TLS数据。现在则可以传入allocator了。这也是为后续的共享栈池做准备。