ps-lite源码学习

ps-lite是一个异步通信的参数服务器。主要提供push,pull,wait操作。

ps-lite底层通信采用ZMQ实现。ZMQ是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ps-lite中van封装了通信操作。

整体结构

postoffice类对van进行了管理,管理了customer的信息,提供worker和server的id转换和查询。postoffice类以单例模式出现。

customer类主要维护了request和response的状态,其中的tracker_成员记录了每一个请求可能发送到了多少服务器,和已经有多少服务器返回。tracker_的下标成为了每一个请求的标识timestamps。wait操作的过程就是tracker_cond_一直等待发送出去的数量和已经返回的数量相等。

通过postoffice和customer,ps-lite实现了简单的simple_app,可以通过简单的通信,每次通信可以发送int型的head,string型的body。

在simple_app的基础上,ps-lite实现了worker, server,scheduler。


worker的push,pull操作

ss.jpg

    push和pull操作最后都会调用send函数,void KVWorker<Val>::Send(int timestamp, bool push, int cmd, const KVPairs<Val>& kvs)。send函数对kvpairs进行切分,因为每个server只保存一部分的参数,每一个slice将发给不同的server。slicer_是一个函数,默认是DefaultSlicer,用户可以自行重写。每个slice将被包装成Message对象,并提交给ps::Van::send函数进行发送。

    在整个KVWorker的send函数中其实没有内存的拷贝,无论是KVPairs被切分还是被放入Message,这些操作都是基于SArray数据结构进行的。SArray是ps中一个共享内存的数组,通过拷贝指针避免数据拷贝。内部指针通过shared_ptr管理。

worker和server的消息处理流程

    woker和server都有一个customer对象,并将自己的process函数注册到customer中成为recv_handle_。Van的Receiving函数接收到Message之后根据customer_id将消息push到对应customer的消息队列recv_queue_中。customer函数的Receiving函数不断的取出消息,调用recv_handle_进行处理,并将对应的请求timestamps的返回数量加1,tracker_[recv.meta.timestamp].second++,Wait操作就是在等待tracker_[timestamp].first == tracker_[timestamp].second满足,first是发送的请求数,second是当前返回了的请求数。worker和server的process最后调用用户传来的callback函数,处理msg里的数据。


关于key value

key必须是唯一的,并且升序排列的。value的长度不定,可以一个key对应一个value,可以一个key对应一个固定长度是数组类型value,可以一个key对应一个变长的数组,这时需要在lens里制定每个value的长度。如果lens为空,value的长度为k=vals.size()/keys.size()。vals存储所有的value,并排向后存。key value对{keys[i], (vals[i*k], ..., vals[(i+1) * k -1])。如果lens不空,key value对{keys[i], (vals[n], ..., vals[lens[i] + n - 1])}。其中n=lens[0] + ... + lens[i - 1]

留言: