分享一种面向大数据处理的分布式缓存系统设计

原创 码农  2020-01-17 11:15:14  阅读 749 次 评论 0 条

面向大数据的平台或系统,底层的存储系统往往无法匹配上层计算应用的读写性能,而设计一个良好的分布式缓存系统将缩小CPU密集型应用和IO密集型应用之间不匹配的性能差距。面向大数据应用的分布式缓存系统,在读写流程、I/O事件驱动并发模型及元数据模型等方面进行了合理设计与优化,并使用fio工具测试了顺序写、随机写、顺序读及随机读场景下的吞吐率与IOPS等性能指标,验证了该分布式缓存系统的高性能优势和应对高并发场景的扩展能力。
大数据处理平台主要由上层的分布式计算组件和底层的分布式存储系统两层构成。存储层的热门产品主要有HDFS、Ceph及OpenStack Swift等,计算层的热门产品主要有MapReduce和Spark等。
以大数据热门项目Hadoop为例,存储组件为HDFS,计算组件是MapReduce或Spark。它的大致工作流程为:HDFS存储海量的数据信息,计算组件启动job作业从HDFS中下载数据后进行数据计算与分析;如果job2需要job1运算后的数据,需要job1将中间结果写入HDFS的block中,此时会产生硬盘甚至跨网络的读写,同时HDFS默认的三副本策略需要将数据链式推送到三个存储节点,从而进一步造成性能的损失。
若将计算节点一侧的DRAM/SSD设备作为底层存储系统的读写缓存,一方面DRAM/SSD设备的读写性能要远远高于机械硬盘,另一方面缓存层与计算节点的网络距离更加接近,所以可以减轻底层存储系统对于上层计算应用的性能制约,从而大幅提高大数据处理的生产力。基于以上原因,研究分布式缓存系统具有极高价值。

01


相关工作


目前成熟的开源分布式缓存系统主要有Memcached、Redis及Alluxio等。

Memcached通过一致性哈希算法完成数据定位,但Memcached并不是严格意义上的分布式。一方面没有完善的容错机制;另一方面Memcached没有持久化机制,故存在断电丢失数据的风险。
相比之下,Redis有着比较完善的分布式机制,支持数据备份,即master-slave主从模式的数据备份,当服务器断电重启后可以通过RDB机制或AOF机制进行数据重放而恢复数据。Alluxio是基于内存的分布式文件系统。相较于Memcached和Redis,Alluxio提供文件接口,存储并维护文件元数据。
元数据主要记录文件的block信息和block所处的缓存服务器信息等。Alluxio异构管理后端大数据文件存储,并统一向大数据计算框架和平台提供数据存储服务。
对于以上解决方案,Memcached并未提供完善的容错机制和高可用机制,且和Redis一样,均未向上层应用提供文件接口。Alluxio的缺陷在于:一方面所有元数据存放于主备master节点的JVM中,那么在海量小文件的存储场景下,同一namespace下元数据规模量存在瓶颈,无法达到十亿或百亿级;另一方面,Alluxio不支持随机读写,故作为分布式存储系统的缓存子系统而言,无法支持更多的应用场景。此外,以上三种解决方案均未很好地针对DRAM+SSD的混合缓存存储进行设计与优化。

基于以上分析,本系统建立在BlueOceanStorage System(BOSS)底层存储的基础上,设计并实现了面向大数据应用的分布式缓存子系统。基于DRAM+SSD混合存储场景,支持全面的读写类型,通过优良的设计大幅提升了底层存储系统的读写性能。

02


系统设计与实现


2.1 系统框架解析

本文设计并实现的分布式缓存系统的各模块组件与BoSS系统各组件之间的集成框架,如图1所示。

分享一种面向大数据处理的分布式缓存系统设计 架构 第1张

图1 缓存系统各组件集成框架
整个系统共存在3种角色,分别为缓存客户端、缓存服务器以及元数据服务器。
2.1.1 缓存客户端(CacheClient)
在生产环境下的大数据平台中,缓存客户端作为BoSS Client库的一部分部署在计算节点上。上层计算应用通过调用BoSSClient库访问BoSS系统,BoSS Client库通过调用CacheClient模块来访问缓存,CacheClient根据文件/对象名请求元数据服务器查找缓存是否命中以及该文件/对象的缓存所在位置,并请求对应的缓存服务器。
2.1.2 缓存服务器(CacheServer)
缓存服务器与BoSSClient并置部署在计算节点上,以daemon的方式持续监听特定的端口,接收Cache Client的数据访问请求。此外,管理本节点上的节点级元数据。每个CacheServer管理本地的DRAM易失性存储设备和SSD持久化存储设备。CacheServer接收到CacheClient的数据访问请求后,根据文件/对象名查找本机内存中维护的元数据hashmap得出该文件/对象在该台服务器的RAMDisk/SSD挂载路径,从而返回DRAM/SSD中该文件/对象的数据流。
2.1.3 元数据服务器(MetaServer)
缓存系统的元数据由MongoDB管理,与BoSS Monitor组件并置部署在3个及以上的监控节点上。每台监控节点上分别部署1个BoSS Monitor组件和1个MongoDB服务。3个BoSS Monitor和3个MongoDB主机之间均基于raft协议实现primary节点选举操作。缓存元数据存放在名为object_cache的collection中,每条元数据document的信息为文件/对象名到对应的缓存服务器节点的映射信息。元数据的添加和删除操作由CacheClient模块控制。
2.2 读写流程分析
当CacheClient发起写请求时,整体流程如下。
(1)CacheClient请求元数据服务器上的cache_server集合,得出当前所有的CacheServer信息,并计算出最佳的CacheServer:

分享一种面向大数据处理的分布式缓存系统设计 架构 第2张

式(1)涉及到的变量的释义如下。
分享一种面向大数据处理的分布式缓存系统设计 架构 第3张为CacheClient到当前CacheServer的网络延迟,若两者在同一主机,则该分享一种面向大数据处理的分布式缓存系统设计 架构 第4张值为0。该值的获取:每台CacheServer主机启动时,会向当前所有CacheServer发起Ping命令,分别得出所有CacheServer的平均网络延迟从而建立map,分享一种面向大数据处理的分布式缓存系统设计 架构 第5张的值则是通过查询该map所得。
分享一种面向大数据处理的分布式缓存系统设计 架构 第6张为每台CacheServer加入集群时写入MongoDB的cache_server集合中的权重值,由用户配置文件中定义,或调用CacheClient的SetServerWeight方法设定。
分享一种面向大数据处理的分布式缓存系统设计 架构 第7张为当前CacheServer上所管理的所有存储设备的剩余空间,通过读取MongoDB的cache_server集合得出。
(2)根据式(1)所选的最佳CacheServer,更新MongoDB中该文件/对象的全局元数据。
(3)CacheClient向该CacheServer发起写请求,给出写类型和文件/对象数据流。若写类型为随机写,由于SSD设备存在擦写次数限制,故将文件/对象写入DRAM,并通过预先定义的同步写/异步写策略,将文件/对象数据持久化到BoSSDataServer中。如果使用异步写策略,则无法保证在持久化过程中该服务器突然宕机而丢失数据的问题。若写类型为顺序写,则将文件/对象数据写入SSD中,向CacheClient返回写入成功的响应后,异步将文件/对象数据更新到底层BoSS DataServer中。
当CacheClient发起读请求时,CacheClient访问MongoDB得出该文件/对象所在的CacheServer地址后,向该CacheServer发起数据读写请求。
根据缓存数据命中情况将有如下流程:
(1)缓存命中本地CacheServer:此时将进行短路读取,绕开socket接口直接读取本地文件系统;
(2)缓存命中远程CacheServer:CacheClient调用socket接口,CacheServer将文件/对象数据流通过网络传输给CacheClient节点,数据拷贝过程通过sendfile()系统调用+DMA的方式进行零拷贝网络传输;
(3)缓存未命中:CacheClient向相应的BoSS DataServer发起socket连接,从底层进行读取。缓存未命中通常发生在第一次从底层BoSS DataServer中加载或者CacheServer将该文件/对象进行缓存替换的情况。
2.3 I/O事件驱动模型
在计算任务较重的情况下,系统会产生大量的随机读写,则缓存系统需要能够承受短时间内的高并发量请求,这是提高性能的关键。程序并发模型的解决方案通常有多进程、多线程、线程池及I/O事件驱动模型等。
本文设计的分布式缓存系统采用的是事件驱动并发模型,基于Go语言编写实现。该处理模块遵循Reactor的设计模式,将I/O协程与事件处理协程相分离。I/O协程采用epoll统一处理所有socket事件和设备I/O事件,事件处理协程采用协程池处理I/O协程解析好的事件消息。这样的设计框架将使得CPU每个核心、存储设备及网卡设备等达到最大程度的并行状态,最大程度地减少系统中的阻塞。
事件处理协程池的结构体定义如下:
typeworkerpool struct {
       workerNum int           // 协程数量
       maxTasks int            //最大任务数量
       taskQueue chan net.Conn // 任务队列
       mutex sync.Mutex        // 任务队列锁
       closed bool         //协程池是否关闭
       done chan struct{}  // 协程池结束运行
}
协程池初始化时创建workerNum个协程,每个协程监听taskQueue channel获取任务,从而处理已准备好的文件描述符。协程池通过donechannel结束协程池中所有协程。添加或删除任务到taskQueue前都需要使用mutex来锁定队列,以避免资源竞争造成错误。
对于设备I/O,采用libaio库来完成异步I/O操作,而异步I/O操作会阻塞于libaio的io_getevent(),故socket的高并发性能将受制于设备I/O的阻塞。因此,本文设计的分布式缓存子系统的I/O处理协程采用epoll统一处理所有socket事件和设备I/O事件。对于异步I/O操作,通过Linux2.6.22及以上版本中的eventfd,可将libaio和epoll事件处理很好地结合,具体处理流程为:
(1)创建一个iocb结构体,用于处理本次异步I/O请求;
(2)创建一个eventfd,并将此eventfd设置到iocb结构中;
(3)调用io_submit()系统调用提交aio请求;
(4)调用epoll_ctl()系统调用将eventfd添加到epoll中;
(5)当eventfd可读/可写时,从eventfd读出完成I/O请求的事件数量,并调用io_getevents()获取到这些I/O事件。
对于异步I/O和网络socket事件的统一处理,事件类型也将通过eventfd的信息来判断。I/O协程将在空闲时间段阻塞在epoll_wait()上,等待事件的完成。当某个事件完成后,通过文件描述符判断是否与aio事件的文件描述符相同。如果不同则为socket事件,正常处理网络数据读写流程;如果相同则为aio事件,调用io_getevent()获取完成的aio请求,并将其回调函数添加到协程池中进行事件的处理。
2.4 元数据模块设计
在实际的应用场景中,大数据平台将会产生海量的小文件,故元数据模块的设计应满足至少十亿级海量小文件的场景。若采用类似于HDFS的master-worker结构,所有元数据信息存储在主备master上,当元数据量较大时,master节点的内存将会成为容量瓶颈。
若采用一致性哈希算法,当增加或移除节点时,会有相当一部分缓存数据需进行迁移,那么数据迁移产生的I/O将会对正常业务I/O造成影响。因此,本文设计的分布式缓存系统的元数据模块基于MongoDB实现。MongoDB可以在数据规模和性能之间取得很好的平衡,从而满足业务需要。
本文设计的缓存子系统主要为两级元数据模型,由全局元数据和节点级元数据组成。全局元数据存放于MongoDB中,记录每个文件/对象映射到每个缓存数据副本所在CacheServer的信息。在选择CacheServer时,同样根据公式选择最佳的CacheServer。CacheServer上存放节点级元数据,在/dev/shm中用一个hashmap存放所有文件/对象到DRAM/SSD设备挂载目录的映射。
在写数据时,流程为:
(1)CacheClient根据式(1)计算最佳的CacheServerIp;
(2)CacheClient将文件/对象与相应的CacheServer的映射信息作为document插入到MongoDB中;
(3)CacheClient更新该CacheServer上的节点级元数据的hashmap。
上述3个过程在CacheClient通过事务保证。若失败则进行回滚;若在事务过程中出错,则在之后的读取过程中或者CacheServer的维护协程中定期清除此元数据。
执行此事务过程中的错误主要分为两种情况。
(1)CacheClient写入MongoDB后发生错误。此时,MongoDB存在全局元数据而相应CacheServer不存在节点级元数据,之后读取该文件/对象时,CacheServer查询自身节点级元数据时未找到该缓存数据,说明之前将该文件/对象全局元数据写入MongoDB后CacheClient发生了宕机或者网络错误,CacheServer则将MongoDB中该文件/对象的全局元数据删除。
(2)CacheClient节点级元数据更新完成后文件/对象流推送过程中失败。每台CacheServer在启动时都会根据实际的缓存数据信息建立自身的节点元数据hashmap,因此可以保证实际的数据读写不会出现差错。此外,在CacheServer运行过程中会启动定期维护的子协程,对节点元数据和实际缓存数据进行check,以消除长时间运行导致的错误累积现象。
读数据时,流程为:
(1)根据文件/对象名和文件/对象哈希值为组合条件查询MongoDB,得出该文件/对象所在CacheServer的IP地址;
(2)向该节点的CacheServer守护进程发送读取请求;
(3)CacheServer根据自身节点级元数据,查询hashmap得出该文件/对象所在的RAMDisk路径或者SSD设备挂载路径;
(4)CacheServer返回文件/对象数据流。

03


性能评测


3.1 测试环境
本文设计并实现的分布式缓存系统相关的部署集群有计算集群、存储集群和MongoDB元数据集群。
3.1.1 硬件方面
每个集群内由3台服务器主机组成,CPU为Inteli9-9900X,主频为3.5 GHz,10 Cores。内存为DDR3,1 600 MHz,容量为16GB。网卡为Intel万兆以太网卡,各主机之间通过万兆光纤宽带相连。计算集群内均配备SAMSUNG 500GB SSD设备,采用NVMe协议。
3.1.2 软件方面
计算集群内的主机上部署CacheServer进程,DRAM设备建立RAMDisk进行数据读写。存储集群内的服务器主机作为BoSS DataServer管理本机上的HDD。元数据集群内的服务器主机上分别部署BoSS Monitor监控进程和MongoDB的守护进程。
3.2 测试方法
本文在计算集群内的主机上使用fio工具调用BoSS CLient库进行读写测试,模拟I/O负载。限于篇幅,本文的测试方案主要侧重于系统的性能,故选用读写类型为顺序读、顺序写、随机读和随机写共4种场景,使用fio工具模拟不同的线程数,分别对使用缓存和不使用缓存时的吞吐率变化情况或者IOPS变化情况进行测试与分析。
3.3 测试结果
图2为顺序写场景下带缓存和无缓存的吞吐率变化情况,带缓存的读写性能略低于无缓存。这是由于无缓存时,I/O负载直接写入BoSS数据服务器节点的HDD上。加上缓存后的写入流程为写入CacheServer的DRAM并持久化到BoSS数据服务器上。因此,并发数较低时,吞吐率略低于无缓存情况。
但是,当并发数较大时,由于缓存子系统的epoll+workerpoll的事件驱动框架,使得CPU、硬盘、网卡达到了最大程度的并行状态。因此,在并发线程数较大时,有缓存的情况可以降低性能抖动。

分享一种面向大数据处理的分布式缓存系统设计 架构 第8张

图2 缓存子系统顺序写性能
图3为随机写场景下带缓存和无缓存的IOPS变化情况。在随机写场景下,I/O负载直接写入DRAM,之后在固定的时间点将RAMDisk中数据持久化到硬盘上。这个过程相当于对I/O序列进行合并排序后写入HDD,故节省了HDD的往返寻道时间。
而HDD的性能瓶颈在于磁头寻道,故将I/O合并排序后相当于顺序读写。磁头只需要按照同一个方向转动,所以IOPS将会大幅增加。同时,在并发度较大时,带有缓存的随机写场景下,性能抖动要比无缓存时好得多。

分享一种面向大数据处理的分布式缓存系统设计 架构 第9张

图3 缓存子系统随机写性能
图4为顺序读场景下带缓存和无缓存的吞吐率变化情况,图5为随机读场景下带缓存和无缓存时的IOPS变化情况。当无缓存时,BoSS系统的顺序读和随机读均是读取HDD。而开启缓存时,读I/O将在BoSS Client侧访问RAMDisk中的缓存;若缓存不存在或者被替换,则对BoSS DataServer侧的HDD进行读取。
若缓存命中且缓存位置在同一计算集群内其他BoSS Client节点,万兆以太网和RAMDisk的读取环境也要比读取BoSS DataServer侧的HDD设备读取性能高。上述测试场景排除了第一次加载冷数据的情况和缓存替换的情况,故带缓存的I/O读写要远比无缓存的I/O读写的性能高。

分享一种面向大数据处理的分布式缓存系统设计 架构 第10张

图4 缓存子系统顺序读性能

分享一种面向大数据处理的分布式缓存系统设计 架构 第11张

图5 缓存子系统随机读性能

04


结 语


本文设计的面向大数据应用的分布式缓存子系统的创新之处在于:(1)NoSQL全局元数据和CacheServer节点级元数据组成的两级元数据模型很好地达到了元数据规模和性能之间的平衡,更加适用于海量小文件的应用场景;(2)I/O事件驱动模型采用epoll协程+workerpool的架构,epoll协程统一管理socket事件和异步I/O事件,workerpool处理请求完成后的回调函数,这种架构使得CPU、网卡、硬盘达到最大程度的并行状态,因此存储系统在高并发情况下依旧能够维持较高的吞吐量,性能平稳,波动较小。
本系统的不足在于未完善缓存数据持久化过程的异步机制和持久化过程中主机断电可能造成的数据丢失问题。在后续工作中,将对异步持久化机制进行完善,使本缓存系统成为更加稳定、可靠、高性能的系统。


本文地址:https://www.itcodeit.com/post/54.html
版权声明:本文为原创文章,版权归 码农 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?