mxnet : parameter-server/ps-lite阅读既要

来源:互联网 发布:javascript对象是什么 编辑:程序博客网 时间:2024/05/19 16:34
说在最前面,ps/ps-lite是mxnet/cxxnet的参数服务器部分,原理上就是一个分布式kv服务,具备range类的pull/push操作;和其他的kv数据库相比(比如redis/leveldb),并没有把精力放在存储的数据结构/内存磁盘的转化之类上,而是大部分精力都用在分布式同步,结构层面,以及传输消息的异步处理和压缩里面了。
后期被定为做类库,可能也是其owner希望业界可以采用这样的结构。与其说是个kv数据库,不如说是分布式kv系统结构类库。和读了redis觉得其数据结构的功底惊为天人不同,ps/ps-lite看完就觉得是个学术界的同学做的系统结构,思路有亮点,结构实现的多少还是有点乱滴。。。当然了C++11用的很溜,每个函数级别的细节实现都还不错。
早年我个人看过淘宝的KV数据库Tair的实现源码(大约在2013年),思路类似,简单来说就是固定分片,每个分片的主机里面的数据更新后,异步同步到具有该分片的其他从分片。ps/ps-lite在这方面的优化其实是在同步时缩减消息内容,甚至多条一起合并。并且引入了mq做中间件,系统的稳定性更好。

1,历史版本
mxnet的parameter-server历史上,主干git可以看到主要的3个版本
a,2015.4月封板的parameter-server,git的说明上也说了停更,并迁移到ps-lite。这个版本里面还多少有一些矩阵类的操作在里面 旧版ps的git
b,2015.10月release的ps-lite v1,此版本和a相比,主要是去掉了真实存储层的部分(file/hdfs等),结构上简化并更深度的进行了抽象
c,master上的ps-lite,基本上进入2017后就没再怎么更新了。比v1版更精简,大概的思路是抽象出好用的公共库 ps-lite的git

2,主要网络部分结构
上述前两版的主要结构方面差别不大,第3版思路也基本一致,但是因为退化为类库就更加从简了。这里主要以b版本为主:
核心是一个叫做Customer的基类,消费者,可以理解为是封装的消息(Message)的收发等待操作,无论是push还是pull都是先异步执行,再异步等待,有3个虚函数,是在不同场景下做不同的继承子类来进行逻辑的部分,分别是请求分片(Slice),处理请求(ProcessRequest)和处理响应(ProcessResponse)。其他的小函数都是流程类的,看名见意,这些小函数基本上就是用下面的exec进行处理。
Executor,执行器,请求异步发送/接受/等待的实际处理部分。异步状态的处理,多线程队列的操作都在这里面。
PostOffice,发送室,executor里面的sys_变量,拥有一个线程安全的队列(c版本的ps-list,可以支持FIFO和优先级队列),然后就是收发各一个线程。可以理解为异步变同步调用的封装。
最后一个主要结构Van,名字直译为厢式货车,或者用车搬运。实际的实现是一个外部mq的收发封装。3个版本里面,都是用的zmq。

另有Scheduler/Server/Worker的实现,没有抽成基类/子类的样子(b版本ps-lite v1),基本具有的操作都是Push和Pull。可以理解为是比Customer更上层的接口层。

3,KV实现
b版本的ps-lite v1中,Customer的主要实现为KV存储型(这个没彻底实现,但留出了架子,比较方便填为本地磁盘型,远程磁盘型,内存型etc,后面的2个内存型都集成此基类),单线程内存版,多线程内存版,以及内存cache版。
其中多线程版本就是把所有的数据按照key hash给多个线程处理,每个线程只处理固定的1/n数据;单线程版本就真的内存kv(std::unordered_map)存了。这两个内存版本和内存cache基本上可以理解为KV的范型不同,实际上实现的差别反倒不大。
在ps-lite之外,mxnet里面的kv实现里面其实还有gpu实现,就是把kv(其实是参数矩阵)存在显存里面,这样应该是便于做在线预测的计算。

4,其他特点
a,主要数据结构是pb定义的
b,有一些Filter抽象,看着是用于在对于远程Node做更新操作时,在数据序列化时进行数据削减用的,比如float类型压缩/整体lz4压缩/重复key合并 etc。没有太仔细一个一个过,看各种软文写的都是为了压缩传输部分,提升吞吐
c,有自己的网络利用率记录
d,Worker里面有一些无copy操作,通过减少复制提升性能;base库里面也应用了C++11右值复制优化。包括还有像是SArray这样的结构类库,也是用来降低复制带来的开销的
e,线程池/线程安全队列的实现较好,一方面用的都是std的锁,看起来很规整,另一方面都是通过信号量触发其他线程通知。此部分实现的值得一看
f,在c版本,ps还额外抽象出了一个dmlc-core的类库,主要就是io.h里面的Stream类,进行了一个流的接口定义,这样方面任何存储形式和这个系统对接转换。思路上和Hadoop里面的抽象方式和近似(其实我是觉得和youdao从早期hadoop分支出来的版本里面的io抽象很一致)
原创粉丝点击