文件系统I/O利用率低调优(上)

酝酿一下


一直以来都在做分布式存储的事情,从最开始的本地文件系统到伪分布式文件系统,从
FastDFS 到 HDFS ,以及到自研的 DFS,说到 DFS 不得不提两点:1.DFS 存什么?2.
DFS
怎么存?那首先,存什么,其实除了原本的文件内容本身外,我们需要将文件的元数据信息以及文件所在的目录信息也保存下来;其次,我们需要考虑的是如何存,目前主流的分布式文件系统都是依照google
提出的论文所开发的,那就是元数据保存在一个进程,文件内容放在另一个进程,进程间通信,实现文件的读写。

今天的主题


文件系统I/O利用率低:目前自研的dfs文件系统I/O吞吐量上不去,那造成这个问题的元凶到底是什么?

现象描述


环境信息:

  • 操作系统:centos7
  • 磁盘:2T SSD
  • CPU: 48 核

首先,作为公司的统一的dfs平台,接收来自业务的读写数据,从业务方跑benchmark,发现tps
只有2k 多,那作为一个这么牛配置的机器,跑这么低的tps我们现在分析一下。

定位步骤


首先,要做性能分析,上来top 先看系统平均负载信息,很低,对应R 状态的进程也只有dfs
的进程 紧接着,看一下iotop,发现只有很少的7-8M/s的文件写入,这是什么鬼。

  1. 初步怀疑是SSD 没配置好,使用dd 命令跑一下现在的磁盘读写速度:

    写性能:dd if=/dev/zero of=/data/test bs=8M count=1000
    读性能:dd if=/data/test of=/dev/null bs=8M count=1000

    根目录下创建data目录,发现每秒都是1.9G/s 这个排除SSD配置的问题

  2. 那我们把焦点放到存储进程的cpu 使用情况上来,使用火焰图分析:

    简单说一下生成火焰图步骤,root 用户:

    1. yum install perf
    2. 安装cmake
    3. 安装 perf-map-agent (这款工具是为了解决perf生成的方法栈展示成地址没有方法名的问题)
    4. jvm 中增加参数 -XX:+PreserveFramePointer
    5. 安装FlameGraph
    6. 使用脚本 gen-flame-graph.sh生成火焰图,如果本地java命令安装不规范,修改脚本43行路径)

    分析火焰图,发现大量的new
    RandomAccessFile(),频繁的创建关闭,影响性能,尝试缓存。

    RandomAccessFile 构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
        
    public RandomAccessFile(File file, String mode)
    throws FileNotFoundException
    {
    String name = (file != null ? file.getPath() : null);
    int imode = -1;
    if (mode.equals("r"))
    imode = O_RDONLY;
    else if (mode.startsWith("rw")) {
    imode = O_RDWR;
    rw = true;
    if (mode.length() > 2) {
    if (mode.equals("rws"))
    imode |= O_SYNC;
    else if (mode.equals("rwd"))
    imode |= O_DSYNC;
    else
    imode = -1;
    }
    }
    if (imode < 0)
    throw new IllegalArgumentException("Illegal mode \"" + mode
    + "\" must be one of "
    + "\"r\", \"rw\", \"rws\","
    + " or \"rwd\"");
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
    security.checkRead(name);
    if (rw) {
    security.checkWrite(name);
    }
    }
    if (name == null) {
    throw new NullPointerException();
    }
    if (file.isInvalid()) {
    throw new FileNotFoundException("Invalid file path");
    }
    fd = new FileDescriptor();
    fd.attach(this);
    path = name;
    open(name, imode);
    }

    那今天先到这,顺便休息下眼睛

坚持原创技术分享,您的支持将鼓励我继续创作!