zoukankan      html  css  js  c++  java
  • 《基于Spark的大数据访存行为跨层分析工具》学习笔记

    这篇文章可以在知网下载,发表时间2020-06-07。以下是个人对这篇文章的阅读笔记和个人感想。
    侵删。

    背景和简介

    通过摘要和介绍,可以了解到Spark的“统一内存管理”模型共分为4层,自上往下分别是Spark层、JVM层、OS层、Hardware层。目前对Spark的性能优化,只停留在某一层。
    个人理解为,对Spark的优化,大多数是通过配置Spark集群的参数、重构代码更适合环境、或者优化JVM、或者配置内存等。都是通过调优某一层来优化Spark。
    更完美的调优,应该是对于某一方向,将OS层、JVM层、Spark层都向其调优,当然三者之间应建立某种联系,达到一个平衡点。

    本文是设计了一个访存行为的跨层分析工具SMTT,建立了上层应用程序的语义与底层物理内存信息的联系。

    设计难点:

    • 每个层都有自己的内存管理机制,需要不破坏其机制的同时,找到每个机制之间的内在联系;
    • 现有对性能分析,都在某一层,即OS层的各个参数、或者JVM层的各个参数,建立联系比较困难;
    • OS层还有别的性能指标,需要排除逻辑上不相关的参数;
    • 管理内存一般采用虚拟地址,造成无法得知物理地址,无法追踪,进而分析。

    设计理念

    Spark层将内存分为保留内存、用户内存、Spark内存。保留内存存放Spark内部对象;用户内存由Spark应用程序使用;Spark内存存储应用程序的数据。其又分为执行内存和存储内存。

    Spark内存分为执行内存和存储内存。执行内存一般用于shuffle开销,存储内存一般用于存储持久化RDD。SMTT针对两种内存设置了两种不同的追踪方案。
    对于执行内存,将RDD和虚拟内存地址建立联系。对于存储内存,剥离其外部数据结构,对数据语义和虚拟地址建立联系。

    SMTT分别对JVM堆内和堆外的数据进行处理,获得虚拟地址。对于堆内获取的内存找到对应的JVM对象,并将JVM对象转换为OS层的虚拟地址,对于堆外的内存,直接找到起始地址,即虚拟地址。最后再将虚拟地址转为物理地址,得到物理页号等信息。

    得到的访问序列信息如下:

    • 访问时间
    • 访问类型
    • Spark语义
    • 虚拟地址
    • 虚拟页信息
    • 物理地址
    • 物理页信息

    最后实验,通过这些信息,分析得到Spark对于内存读写的负载情况。

    执行内存追踪方案

    1. 在Task中,获取Writer的Hash码和RDD信息,将两者写入一张Hash表,得到Writer和RDD信息的关系;
    2. 在Writer中,将所用Sorter的Hash码和当前的Writer的Hash码写入张Hash表,这时候建立起RDD信息和Sorter之间的联系;
    3. 在Sorter中,将当前Sorter的Hash码,以及虚拟内存地址发送给SMTT,这时候建立起RDD信息和虚拟内存地址的联系;
    4. 根据OS页表,通过虚拟内存地址得到物理内存信息;
    5. 将RDD信息、虚拟地址、物理地址信息作为一条记录保存到文件。

    存储内存追踪方案

    MemoryStore对象提供了统一的存/取接口。内存维护了一个以Spark的BlockID对象为键、以MemoryEntry对象为值的Hash表。其中BlockID对象是RDDID和分区ID按一定格式的组合。MemoryEntry用于描述被存储的数据。其内部还有一个Java对象ByteBuffer数组,每一个ByteBuffer对象内部有一个存储数据的字节数组。

    1. 在MemoryStore对象内部,对Hash表进行存取,把BlockID对象和MemoryEntry对象给SMTT;
    2. 获取数据对象中的ByteBuffer数组
    3. 通过Unsafe对象获取字节数组在JVM的起始地址;
    4. 根据头信息长度获取数据的虚拟地址;
    5. 访问页表,虚拟地址转为物理地址
    6. 最后把各个信息写入文件

    Spark计算过程追踪

    这对于理解Spark的运行有很好的的帮助。首先应该知道的是,DAGscheduler会将job分为很多个阶段stage。

    每个阶段的执行起点是当前阶段的最后一个RDD,这个RDD的每一个分区会交给一个Task线程。Task会调用最后一个RDD的iterator()方法获得其负责处理分区数据的迭代器,这个iterator()方法会调用当前RDD的computer()方法,递归下去调用到第一个RDD的compute()方法。第一个RDD的compute()方法会返回一个文本数据的迭代器,就是读取数据,返回给下一个RDD,下一个RDD会新创建一个迭代器对象Iter,并重写next()方法,递归返回给最后一个RDD。最终Task拿到迭代器,每调用一次next()方法,就从文件系统读取一条记录,并通过上述转换函数。

    实验评测

    本文以机器学习、SQL查询、图计算、流计算的应用,以读写RDD的评测结果为例,评测借助SMTT的追踪分析不同程序的不同特征的效果。

    得到小结论:写开销略高于读开销,这是因为RDD被设计为只读的,RDD被持久化后可以重复读取,而写得不断开销。

    最终结论:

    • 各负载的RDD内存占用率差别较大,LR,SVM,SVDPP,TC内存占用率较高,PR,RR,PVS内存占用率较低,MF占用率最低。
    • 相比单节点集群,多节点内存利用率较低。
  • 相关阅读:
    FarPoint FpSpread控件的使用收藏
    在Oracle中使用Guid
    oracle 语句的妙用例子
    让服务器iis支持.apk文件下载的设置方法
    oracle 自动生存清库脚本
    winform 消息通讯组件实习
    在css中使用边框做三角形
    JavaScript闭包和ajax
    JavaScript面向对象
    正则表达式
  • 原文地址:https://www.cnblogs.com/chenshaowei/p/13129742.html
Copyright © 2011-2022 走看看