IOBuf是否能支持连续的内存避免内存拷贝
brpc目前从socket读取到的数据是放在IOBuf中的,但是由于IOBuf是一个非连续的内存缓冲区,如果用户需要保证接收到的是一块连续的内存的话需要进行一次内存拷贝,但是在大数据量的场景下内存拷贝存在性能瓶颈,请问有什么方法可以避免这次内存拷贝呢
可以看看IOBuf的append_user_data函数
可以看看IOBuf的append_user_data函数
我在数据发送端通过append_user_data避免了发送端的数据拷贝,但是在接收端拿到的就是IOBuf,从网络拿到的数据放到IOBuf这一步已经是不连续的内存了,这里接收端能保证接收到连续的内存来避免拷贝吗
IOBufAsZeroCopyOutputStream可以满足需求吗
可以看看IOBuf的append_user_data函数
我在数据发送端通过append_user_data避免了发送端的数据拷贝,但是在接收端拿到的就是IOBuf,从网络拿到的数据放到IOBuf这一步已经是不连续的内存了,这里接收端能保证接收到连续的内存来避免拷贝吗
如果要接收端能拿到连续的buf,意味着接收端在接收body之前,需要从协议头里获取body的长度,然后分配出相应长度的内存,再用这段内存来接收网络数据。这个逻辑应该是协议相关的,需要修改协议的实现,仅仅改IOBuf是不够的
可以看看IOBuf的append_user_data函数
我在数据发送端通过append_user_data避免了发送端的数据拷贝,但是在接收端拿到的就是IOBuf,从网络拿到的数据放到IOBuf这一步已经是不连续的内存了,这里接收端能保证接收到连续的内存来避免拷贝吗
如果要接收端能拿到连续的buf,意味着接收端在接收body之前,需要从协议头里获取body的长度,然后分配出相应长度的内存,再用这段内存来接收网络数据。这个逻辑应该是协议相关的,需要修改协议的实现,仅仅改IOBuf是不够的
请问一下这一块是需要在哪里进行修改呢,我理解这一层在自定义协议是没法完成的,因为自定义协议的接口都是基于IOBuf,理论上是否是需要修改OnNewMessages这个函数的实现,例如申请一块连续内存,然后通过append_user_data保证接收端接收到的内存是连续的?这个问题的背景是因为在高性能计算的场景下,向量化的计算需要保证内存是连续的,现在其实多了一层内存拷贝的开销,这在大数据量的场景下其实有比较大的性能损耗
IOBufAsZeroCopyOutputStream可以满足需求吗
不太能满足,IOBufAsZeroCopyOutputStream只是在逻辑上wrap了一下,但是其实物理内存还是不连续的
请问一下这一块是需要在哪里进行修改呢,我理解这一层在自定义协议是没法完成的,因为自定义协议的接口都是基于IOBuf,理论上是否是需要修改OnNewMessages这个函数的实现,例如申请一块连续内存,然后通过append_user_data保证接收端接收到的内存是连续的?这个问题的背景是因为在高性能计算的场景下,向量化的计算需要保证内存是连续的,现在其实多了一层内存拷贝的开销,这在大数据量的场景下其实有比较大的性能损耗
可能需要大改,包括IOBuf、Socket、InputMessenger、协议 这里还有个麻烦就是brpc支持多协议,所以一开始不知道要准备多大的buf,只能先随便读一段数据再尝试逐个协议解析,这时候可能已经读进来一部分body了,那么后续再读就不连续了
请问一下这一块是需要在哪里进行修改呢,我理解这一层在自定义协议是没法完成的,因为自定义协议的接口都是基于IOBuf,理论上是否是需要修改OnNewMessages这个函数的实现,例如申请一块连续内存,然后通过append_user_data保证接收端接收到的内存是连续的?这个问题的背景是因为在高性能计算的场景下,向量化的计算需要保证内存是连续的,现在其实多了一层内存拷贝的开销,这在大数据量的场景下其实有比较大的性能损耗
可能需要大改,包括IOBuf、Socket、InputMessenger、协议 这里还有个麻烦就是brpc支持多协议,所以一开始不知道要准备多大的buf,只能先随便读一段数据再尝试逐个协议解析,这时候可能已经读进来一部分body了,那么后续再读就不连续了
协议解析的时候需要的应该只是一小部分body吧,例如brpc的协议其实只需要前12个字节就可以确认了,后续的内存可以先申请,然后把前12个字节的数据重新set一下就可以了吧,不知道这个理解是否正确?
协议解析的时候需要的应该只是一小部分body吧,例如brpc的协议其实只需要前12个字节就可以确认了,后续的内存可以先申请,然后把前12个字节的数据重新set一下就可以了吧,不知道这个理解是否正确?
不是把前12个字节的数据重新set一下,是要把提前读到的部分body先吐出来,然后写入一段连续的内存,再用这段连续内存进行后续的写入
@WingsGo 请问下你这里大数据量指的是单个rpc payload很大还是qps很高.
@WingsGo 请问下你这里大数据量指的是单个rpc payload很大还是qps很高.
单个RPC的payload比较大
协议解析的时候需要的应该只是一小部分body吧,例如brpc的协议其实只需要前12个字节就可以确认了,后续的内存可以先申请,然后把前12个字节的数据重新set一下就可以了吧,不知道这个理解是否正确?
不是把前12个字节的数据重新set一下,是要把提前读到的部分body先吐出来,然后写入一段连续的内存,再用这段连续内存进行后续的写入
@wwbmmm 如果考虑做一些特殊处理的话,是可以放弃多协议的支持去实现这个模式的?
@wwbmmm 如果考虑做一些特殊处理的话,是可以放弃多协议的支持去实现这个模式的?
应该是可以的
@chenzhangyi @wwbmmm
我理解对于baidu_rpc协议来说,meta和payload的length是在协议头就已经确定好了的,这样可以修改append_from_file_descriptor,在从socket的fd读取数据的时候,将allocate内存的方法提供给用户,然后通过append_user_data就可以在recever端减少这一次拷贝了吧?我可以提一个PR来实现一下,不知道这样的方案是否可行?
@chenzhangyi @wwbmmm 我理解对于baidu_rpc协议来说,meta和payload的length是在协议头就已经确定好了的,这样可以修改append_from_file_descriptor,在从socket的fd读取数据的时候,将allocate内存的方法提供给用户,然后通过append_user_data就可以在recever端减少这一次拷贝了吧?我可以提一个PR来实现一下,不知道这样的方案是否可行?
可以考虑给iobuf加个reserve_continuous_buffer(int size)方法,然后由协议来控制预留buffer的大小
@chenzhangyi @wwbmmm 我理解对于baidu_rpc协议来说,meta和payload的length是在协议头就已经确定好了的,这样可以修改append_from_file_descriptor,在从socket的fd读取数据的时候,将allocate内存的方法提供给用户,然后通过append_user_data就可以在recever端减少这一次拷贝了吧?我可以提一个PR来实现一下,不知道这样的方案是否可行?
可以考虑给iobuf加个reserve_continuous_buffer(int size)方法,然后由协议来控制预留buffer的大小
那也就是说可以这么实现?在协议层直接预先分配内存,后续从fd读取的数据可以保证不会超过这个大小,这样就能保证block的数量始终保持为1,然后在读取数据的时候通过fetch方法来避免拷贝,我理解这样的改动是最小的?
else if (source->length() < sizeof(header_buf) + body_size) { // 预先分配size大小的内存,并作为一个block放入source中,然后将source->length()的内容拷贝进这个block里 source-> reserve_continuous_buffer(sizeof(header_buf) + body_size) return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); }
那也就是说可以这么实现?在协议层直接预先分配内存,后续从fd读取的数据可以保证不会超过这个大小,这样就能保证block的数量始终保持为1,然后在读取数据的时候通过fetch方法来避免拷贝,我理解这样的改动是最小的?
else if (source->length() < sizeof(header_buf) + body_size) { // 预先分配size大小的内存,并作为一个block放入source中,然后将source->length()的内容拷贝进这个block里 source-> reserve_continuous_buffer(sizeof(header_buf) + body_size) return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); }
可以这样试试
mark,遇到相同的问题
mark
mark
mark