基于hiactor实现MapReduce

背景

MapReduce 原理介绍与开发实战
MapReduce源码解析(二)MapTask
MapReduce终篇(5)—— Task的运行详解

模仿MapReduce的接口,是有一定意义的。但是像hadoop那样将中间结果落盘,似乎没必要模仿。或许可以借鉴下Spark

hiactor
程序员创建编写actor的类文件,运行hiactor的脚本,来codegen产生actor的代理类的文件(类似于rpc中的stub)

想实现MapReduce作为中间层框架:

  • 节点们需要被组织起来成为一个整体。另外节点也需要些宏观的信息,如下游节点的个数,节点间消息传递也需要宏观的信息,如下游节点的地址
  • map和reduce等节点,需要接受用户传入的自定义函数,作为回调函数。
  • map和reduce需要接受不同类型的kv和输出不同类型的kv

宏观组织

  1. JobManager节点接受任务的配置,按需启动多个(0个、1个或更多个)MapManager节点和ReduceManager节点等。
  2. MapManager启动多个MapWorker,ReduceManager启动多个ReduceWorker。
  3. MapWorker和ReduceWorker是真正干活的actor,提供init方法(可以是actor的方法,接受个消息),以便于Manager进行配置

接受回调函数

考虑到用户自定义代码,需要分发到不同主机上,可以考虑:

  1. 用户编写符合一定规则的函数,并编译成动态库
  2. map和reduce节点在被调用init方法时,接受关于动态库里函数的信息,如动态库名字和函数符号名字等
  3. 在init方法里使用动态库,基于dlopendlsym等,显式的加载动态库里的函数

或许可以使用Tiny C Compiler做JIT,接受段c语言文本,编译成代码使用?

回调函数的输入输出类型

用户自定义函数的输入输出类型,与用户要实现的上层业务高度相关,通常多种多样,并且多半是个结构体,而非标量或数组,框架在在编译期是无法感知到这些类型。要想知道这些运行期的各种状态类型的。通常需要反射模板等技术。但c++一直以来基本上就不支持反射机制。

其实反射最大的作用就是序列化、解序列化一个结构体,然后就能够在各个模块之间进行通信交互,不管是跨进程还是跨机器也好。其实可以使用protobuf来实现消息的序列化,这样开发起来,基本上就不用考虑反射和为每个消息手写序列化代码了。

所以,回调函数的输入和输出均为传入字节数组(实际是protobuf序列化后的数据)。在用户自定义函数里进行输入的反序列化和输出的序列化操作。

ps:有些像其他框架提供api,该api接受回调函数,该回调函数的参数得是void*,在回调函数里将void*转换成真正的类型的指针。

代价就是需要用户保证相关类型转换代码不用写错,编译器不会做检查。

其他

用户是指基于MapReduce做二次开发的程序员。

观察到,当代码里调用代理类实例时,hiactor框架才创建actor实例。

用户代码里是与actor代理类打交道。我们把actor类定义成模板类,没有意义。

seastar介绍及源码分析

posted @ 2023-10-10 10:20  Tifa_Best  阅读(24)  评论(0编辑  收藏  举报