分布式缓存介绍
在Yarn中,分布式缓存是一种分布式文件分发与缓存机制,类似于MRv1中的Distrubuted Cache,其主要作用就是将用户应用程序执行时所需的外部文件资源自动透明的下载缓存到各个节点,从而省去了用户手动部署这些文件麻烦。
YARN分布式缓存工作流程如下:
- 客户端将应用程序所需的文件资源(外部字典、JAR包、二进制文件)提交到HDFS上。
- 客户端将应用程序提交到RM上。
- RM将与某个NM进行通信,启动应用程序AM,NM收到命令后,首先从HDFS上下载文件(缓存),然后启动AM。
- AM与RM通信,以请求和获取计算资源。
- AM收到新分配到的计算资源后,与对应的NM通信,以启动任务。
- 如果应用程序第一次在该节点上启动任务,NM首先从HDFS上下载文件缓存到本地,然后启动任务。
- NM后续收到启动任务请求后,如果文件已在本地缓存,则直接执行任务,否则等待文件缓存完成后再启动。
各个节点上的缓存文件由对应的NM管理和维护。在Hadoop中,分布式缓存并不是将文件缓存到集群中各个节点的内存中,而是将文件缓存到各个节点的磁盘上,以便执行任务时直接从磁盘上读取文件。
资源可见性和分类
分布式缓存机制是由各个NM实现的,主要功能是将应用程序所需的文件资源缓存到本地,以便后续任务的使用,资源缓存是用时触发的,也就是第一个用到该资源的任务触发,后续任务无需再进行缓存,直接使用即可;
根据可见性,NM将资源分为三类:
- Public:节点上所有的用户都可以共享该资源,只要有一个用户的应用程序将着这些资源缓存到本地,其他所有用户的所有应用程序都可以使用;
- Private:节点上同一用户的所有应用程序共享该资源,只要该用户其中一个应用程序将资源缓存到本地,该用户的所有应用程序都可以使用;
- Application:节点上同一应用程序的所有Container共享该资源;
根据资源类型,NM向资源分为三类:
- archive:归档文件,支持.jar、.zip、.tar.gz、.tgz、.tar的5种归档文件;
- file:普通文件,NM只是将这类文件下载到本地目录,不做任何处理;
- pattern:以上两种文件的混合体;
YARN是通过比较resource、type、timestamp和pattern四个字段是否相同来判断两个资源请求是否相同的。如果一个已经被缓存到各个节点上的文件被用户修改了,则下次使用时会自动触发一次缓存更新,以重新从HDFS上下载文件。
分布式缓存完成的主要功能是文件下载,涉及大量的磁盘读写,因此整个过程采用了异步并发模型加快文件下载速度,以避免同步模型带来的性能开销。
分布式缓存实现
NodeManager采用轮询的分配策略将这三类资源存放在yarn.nodemanager.local-dirs指定的目录列表中,在每个目录中,资源按照以下方式存放:
- PUBLIC资源:存放在${yarn.nodemanager.local-dirs}/filecache/目录下,每个资源将单独存放在以一个随机整数命名的目录中,且目录的访问权限均为0755。
- PRIVATE资源:存放在${yarn.nodemanager.local-dirs}/usercache/${user}/filecache/目录下,(其中${user}是应用程序提交者,默认情况下,均为NodeManager启动者),每个资源将单独存放在以一个随机整数命名的目录中,且目录的访问权限均为0710。
- APPLICATION资源:存放在${yarn.nodemanager.local-dirs}/usercache/${user}/${appcache}/${appid}/filecache/目录下(其中${appid}是应用程序ID),每个资源将单独存放在以一个随机整数命名的目录中,且目录的访问权限均为0710;
其中Container的工作目录位于${yarn.nodemanager.local-dirs}/usercache/${user}/${appcache}/${appid}/${containerid}目录下,其主要保存jar包文件、字典文件对应的软链接。
其根据不同的可见性实现的缓存机制如下:
- PUBLIC资源本地化:是由PublicLocalizer实现的,在NodeManager进程中会有一个线程池PublicLocalizers,其个数是由yarn.nodemanager.localizer.fetch.thread-count决定,线程池的大小决定并行下载PUBLIC资源的线程最大个数。当PublicLocalizer本地化PUBLIC资源时,会通过检查这些资源在HDFS上的权限来确定所申请的资源确实为PUBLIC。只要有资源不符合就拒绝本地化。PublicLocalizer能安全的从HDFS上下载资源是向ContainerLaunchContext传递了证书。
- PRIVATE/APPLICATON资源的本地化:是由ContainerLocalizer实现的,不同与PUBLIC的PublicLocalizer实现。PublicLocalizer是直接在NodeManager中启动一个线程池进行本地化,而ContainerLocalizer出于安全问题,并没有在NodeManager进程中直接实现,而是在continer中实现的。并且ContainerLocalizer是一个单独的进程,这个进程由LocalizerRunner线程管理,LocalizerRunner是NodeManager中的一个线程,只要某个container有资源还没有下载,那么此container就会触发一个LocalizerRunner。
- 当某个container第一次请求PRIVATE/APPLICATION类型的本地资源时,如果没有在LocalResourcesTracker中找到,则加入pending-resources列表。随后是否需要创建LocalizerRunner线程取决于是否有必要下载资源,如果需要就将本地资源加入LocalizerRunner维护的pending-resources列表。
- NodeManager在安全模式时,本地资源本地化时需要所用的user是application的提交用户而不是NodeManager的启动用户。因此LocalizerRunner会以application提交者的身份启动LinuxContainerExecutor(LCE)进程,然后LCE会执行ContainerLocalizer下载资源。ContainerLocalizer启动之后会与NodeManager维持一个心跳,通过心跳,LocalizerRunner给ContainerLocalizer分配需要下载的资源或者停止ContainerLocalizer进程,而ContainerLocalizer会通知LocalizerRunner自己的下载进度。如果资源下载失败,这个资源将会从LocalResourcesTracker中移除,并且container最终也会失败。如果下载成功,LocalizerRunner会通过心跳给ContainerLocalizer另一个资源进行下载,直到所有的资源都下载完。
最后,NodeManager为了避免缓存的文件过多导致磁盘“撑爆”,其会定期清理过期的缓存文件,具体方法如下:每隔一定时间yarn.nodemanager.localizer.cache.cleanup.interval-ms(单位是毫秒,默认值是10×60×1000,即10分钟)启动一次清理工作,确保每个缓存目录中文件容量小于yarn.nodemanager.localizer.cache.target-size-mb(单位是MB,默认是10240,即10GB),如果超过该值,则采用LRU(Least Recently Used)算法清除已不再使用的缓存文件,直至文件容量低于设定值。