从磁盘原理理解文件读写优化

目录

 

案例背景

磁盘结构

盘面

磁道

柱面

启停区或着陆区(LandingZone)

扇区

读写过程

 磁盘碎片的产生(1) 

希捷硬盘读写性能测试报告

 文件碎片

文件碎片定义

产生 原因

文件碎片和连续文件读取性能对比(100M相同内容的文件)

解决方案

避免随机读 写

随机读写危害

随机读写解决方案

异步刷盘和同步刷盘

同步刷盘

异步刷盘

小文件性能影响及解决方案

小文件性能影响

小文件解决方案

并发写提高数据入盘性能

广义并发写

狭义并发写

读写分离

读写分离的必要性

读写分离的解决方案

业界优秀案例

K afka的log文件系统

topic中partition存储分布

采用优化策略

数据过期删除及log大小固定策略

小文件合并增大吞吐量


案例背景

目前影响文件读写性能的点在于文件碎片,大量小文件,文件刷盘方式,随即读写等。基于上述几类瓶颈点给于解决方案。以便解决业务线现场大量的语音文件接入。

磁盘结构

硬盘在逻辑上被划分为磁道、柱面以及扇区.下图所示:

从磁盘原理理解文件读写优化_第1张图片从磁盘原理理解文件读写优化_第2张图片

 

数据的读/写按柱面进行,而不按盘面进行。也就是说,一个磁道写满数据后,就在同一柱面的下一个盘面来写,一个柱面写满后,才移到下一个扇区开始写数据。读数据也按照这种方式进行,这样就提高了硬盘的读/写效率。

盘面

硬盘的盘片一般用铝合金材料做基片,高速硬盘也可能用玻璃做基片。硬盘的每一个盘片都有两个盘面(Side),即上、下盘面,一般每个盘面都会利用,都可以存储数据,成为有效盘片,也有极个别的硬盘盘面数为单数。每一个这样的有效盘面都有一个盘面号,按顺序从上至下从“0”开始依次编号。在硬盘系统中,盘面号又叫磁头号,因为每一个有效盘面都有一个对应的读写磁头。硬盘的盘片组在2~14片不等,通常有2~3个盘片,故盘面号(磁头号)为0~3或 0~5。

磁道

    磁盘在格式化时被划分成许多同心圆,这些同心圆轨迹叫做磁道(Track)。磁道从外向内从0开始顺序编号。硬盘的每一个盘面有300~1 024个磁道,新式大容量硬盘每面的磁道数更多。信息以脉冲串的形式记录在这些轨迹中,这些同心圆不是连续记录数据,而是被划分成一段段的圆弧,这些圆弧的角速度一样。由于径向长度不一样,所以,线速度也不一样,外圈的线速度较内圈的线速度大,即同样的转速下,外圈在同样时间段里,划过的圆弧长度要比内圈 划过的圆弧长度大。每段圆弧叫做一个扇区,扇区从“1”开始编号,每个扇区中的数据作为一个单元同时读出或写入。一个标准的3.5寸硬盘盘面通常有几百到几千条磁道。磁道是“看”不见的,只是盘面上以特殊形式磁化了的一些磁化区,在磁盘格式化时就已规划完毕。

柱面

所有盘面上的同一磁道构成一个圆柱,通常称做柱面(Cylinder),每个圆柱上的磁头由上而下从“0”开始编号。数据的读/写按柱面进行,即磁 头读/写数据时首先在同一柱面内从“0”磁头开始进行操作,依次向下在同一柱面的不同盘面即磁头上进行操作,只在同一柱面所有的磁头全部读/写完毕后磁头 才转移到下一柱面(同心圆的再往里的柱面),因为选取磁头只需通过电子切换即可,而选取柱面则必须通过机械切换。电子切换相当快,比在机械上磁头向邻近磁道移动快得多,所以,数据的读/写按柱面进行,而不按盘面进行也就是说,一个磁道写满数据后,就在同一柱面的下一个盘面来写,一个柱面写满后,才移到下一个扇区开始写数据。读数据也按照这种方式进行,这样就提高了硬盘的读/写效率。一块硬盘驱动器的圆柱数(或每个盘面的磁道数)既取决于每条磁道的宽窄(同样,也与磁头的大小有关),也取决于定位机构所决定的磁道间步距的大小。

启停区或着陆区(LandingZone)

磁头靠近主轴接触的表面,即线速度最小的地方,是一个特殊的区域,它不存放任何数据

扇区

操作系统以扇区(Sector)形式将信息存储在硬盘上,每个扇区包括512个字节的数据和一些其他信息。一个扇区有两个主要部分:存储数据地点的标识符和存储数据的数据段。

读写过程

即一次访盘请求(读/写)完成过程由三个动作组成:
       1)寻道(时间):磁头移动定位到指定磁道 ,经验值在3~15ms
       2)旋转延迟(时间):等待指定扇区从磁头下旋转经过 60*1000/7200/2 = 4.17ms(7200rpm硬盘
       3)数据传输(时间):数据在磁盘与内存之间的实际传输(200M/S,希捷4TB硬盘

因此在磁盘上读取扇区数据(一块数据)所需时间:

      Ti/o=tseek +tla + n *twm

其中:

tseek 为寻道时间

tla为旋转时间

twm 为传输时间

 磁盘碎片的产生(1) 

俗话说一图胜千言,先用一张ACSII码图来解释为什么会产生磁盘碎片。

                                        从磁盘原理理解文件读写优化_第3张图片

这里所说的方法二就像是我们的windows系统的存储方式,每个文件都是紧挨着的,但如果其中某个文件要更改的话,那么就意味着接下来的数据将会被放在磁盘其他的空余的地方。
如果这个文件被删除了,那么就会在系统中留下空格,久而久之,我们的文件系统就会变得支离破碎,碎片就是这么产生的。

Linux文件碎片基本很少,Linux的ext2,ext3,ext4文件系统——ext4是Ubuntu和目前大多发行版所采用的文件系统——会以一种更加智能的方式来放置文件。Linux的文件系统会将文件分散在整个磁盘,在文件之间留有大量的自由空间,而不是像Windows那样将文件一个接一个的放置。当一个文件被编辑了并且变大了,一般都会有足够的自由空间来保存文件。如果碎片真的产生了,文件系统就会尝试在日常使用中将文件移动来减少碎片,所以不需要专门的碎片整理程序。

希捷硬盘读写性能测试报告

硬盘规格:希捷新酷鱼2TB硬盘(3碟版)的HD Tune读取

                             从磁盘原理理解文件读写优化_第4张图片

上述出现原因从磁盘结构上看,角速度一致,线速度由于半径越来越小,导致读写速度下降。

 文件碎片

文件碎片定义

文件碎片是因为文件被分散保存到整个磁盘的不同地方,而不是连续地保存在磁盘连续的中形成的

产生 原因

(1)在文件操作过程中,Windows系统可能会调用虚拟内存来同步管理程序,这样就会导致各个程序对硬盘频繁读写,从而产生文件碎片。

(2)还有一种情况就是当中间的一个扇区内容被删除后,新写入一个较小的文件,这样在这个文件两边就会出现一些空间,这时候再写入一个文件,两段空间的任意一部分都不能容纳该文件,这时候就需要将文件分割成两个部分,碎片再次产生了。

(3)最常见的就是下载电影之类的大文件,这期间大家一般都会处理一下其它事情,而下载下来的电影文件被迫分割成若干个碎片存储于硬盘中。因此下载是产生碎片的一个重要源头。还有就是经常删除、添加文件,这时候如果文件空间不够大,就会产生大量的文件碎片,随着文件的删改频繁,这种情况会日益严重。

文件碎片和连续文件读取性能对比(100M相同内容的文件)

                                    从磁盘原理理解文件读写优化_第5张图片

从上图看出,在采用nio读取文件的时候,buffer的大小设置为512kb,读取性能最高,文件碎片读取为80ms,连续文件读取60ms,得知,文件碎片严重影响读写性能。

解决方案

在我们目前开发的文件存储系统,由于各种原因,很难避免文件碎片的产生。基于迅雷下载思想的启发,我们在从小文件读取数据写入大文件的时候,可以事先分配好大文件的尺寸,占据固定大小的连续的磁盘分区。这样在采用修改的方式,把每个字节修改成指定的数据,会得到连续完整的文件,避免磁盘碎片的产生。

分配尺寸方式:RandomAccessFile raf = new RandomAccessFile(file, “rw”);

              Raf.setLength(1024*1024*1024);

这样可以分配1G大小的文件,经测试1ms左右的时间可以完成上述分配。

避免随机 

随机读写危害

由磁盘结构一节可知,数据写入和读取时间由寻址,磁头旋转,数据传输组成,如果随即读写的话,每一次数据读写时间=寻址(12ms)+磁头旋转(3ms)+数据传输(1ms,小文件),如果是顺序读写时间=数据传输。

随机读写解决方案

磁盘分区循环写入数据,先将一块磁盘分成3个分区,1分区写完,写2分区,2分区写完,写3分区,3分区写完,将1分区快速格式化,然后将数据写入1分区。

                                             从磁盘原理理解文件读写优化_第6张图片

异步刷盘和同步刷盘

同步刷盘

采用零拷贝的方式,采用nio的强制刷盘策略,等待文件真正落盘后,才会继续代码流程,小文件性能大概在2~3M/s左右。

异步刷盘

javaIo的普通刷盘方式,就是一种异步刷盘,当调用文件IO的flush的方式时,其实是向内核发送一条刷盘指令,直接返回。小文件性能在13M/S左右。

小文件性能影响及解决方案

小文件性能影响

文件读写时间=寻址+旋转延迟+数据传输,小文件读写的性能瓶颈在寻址上。

小文件200kb:寻址时间=12ms

              旋转延迟=3ms

              数据传输=1ms

上述读写性能在0.2M * (1/0.016)=12.5M/S,IOPS=62次/s

大文件 20GB:  寻址时间=12ms

              旋转延迟=3ms

              数据传输=20*1024/200=102400ms

上述读写性能在 20*1024M *(1/102415) = 200M/s,基本可以发挥文件读写极致,瓶颈在数据传输上,这是我们想要的效果。

小文件解决方案

将小文件合并成大文件进行存储,这样读取性能就会大大提高,目前kafka的log存储和读取原理采用的就是此种方式。

                                      从磁盘原理理解文件读写优化_第7张图片

数据块定义:起始字符,版本标识,chunkSize,subChunkId, subChunkSize,Data,结束标记。

存储:存储小文件的时候,首先抽取一个可存入大文件路径,   封装小文件的元数据和数据信息,追加到大文件的尾部。返回一个加密后的ID,这个id包含小文件的位置和基本信息。

读取:读取根据id进行读取,也可遍历读取。

删除:在元数据中加标记,不真正删除文件,避免文件碎片,   后期统一格式化处理。

并发写提高数据入性能

广义并发写

一块磁盘启用多个线程进行写数据,根据硬盘知识可知,一块硬盘有很多磁头,但是只有一个有效磁头在运作,多个线程会造成磁头争夺,导致写入性能下降。

狭义并发写

 一台linux机器可以多块硬盘,比如4块,为了避免争夺磁头,每块硬盘最多只能由一个线程操作,这样就可以同时写入4个数据分别落到不同的硬盘中,实现方式架构如下图:

                                                    从磁盘原理理解文件读写优化_第8张图片

Queue:数据硬盘目录,四块硬盘,四个目录,阻塞队列

线程池:根据硬盘数量分配线程池线程数量,四块硬盘,四个线程。

流程:当数据准备入库,获取线程,线程从队列中请求入库硬盘,根据请求地址入库。

读写分离

读写分离的必要性

 根据硬盘知识可知,一块硬盘有很多磁头,但是只有一个有效磁头在运作,如果同时有数据进行读和写操作,就会造成磁头争夺,导致性能下降。

读写分离的解决方案

目前同一进程读写分离可以实现,不同进程的读写分离无法实现。

业界优秀案例

K afka的log文件系统

topic中partition存储分布

Kafka集群只有一个broker,xxx/message-folder为数据文件存储根目录,在Kafka broker中server.properties文件配置(参数log.dirs=xxx/message-folder),例如创建2个topic名 称分别为report_push、launch_info, partitions数量都为partitions=4

存储路径和目录规则为:

xxx/message-folder

  |--report_push-0
  |--report_push-1
  |--report_push-2
  |--report_push-3
  |--launch_info-0
  |--launch_info-1
  |--launch_info-2
  |--launch_info-3

 

在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。

采用优化策略

kafka是一个高吞吐量分布式消息系统,并且提供了持久化。其高性能的有两个重要特点:1、并发,2、连续读写性能远高于随机读写。

优化着重于并发策略,下面举两个案例说明:

  1. 一个topic分成多个patition,磁盘总数是一块,这样多个分区会往同一块磁盘写入数据,造成广义并发写,磁头争夺,性能急剧下降。

  2. 一个topic分成多个patition,磁盘总数是多块,这样每一个分区会写一块硬盘,造成狭义并发写,性能得到保障。

数据过期删除及log大小固定策略

Kafka并未提供删除数据的api,可以设置过期时间,kafka根据过期时间自动删除。

Kafka的log大小固定,所以一块盘中的log数据基本上都是一样大,根据文件写入规则,基本上不会产生文件碎片。

小文件合并增大吞吐

众所周知,kafka 是一个消息中间件,存储采用固定大小的log系统,当我们将小文件数据或者是一条条日志存储到kafka中,都会被写到指定的log文件,这样小文件就会被组合成大文件。

每个log entry格式为"4个字节的数字N表示消息的长度" + "N个字节的消息内容";每个日志都有一个offset来唯一的标记一条消息,offset的值为8个字节的数字,表示此消息在此partition中所处的起始位置..每个partition在物理存储层面,有多个log file组成(称为segment).segment file的命名为"最小offset".kafka.例如"00000000000.kafka";其中"最小offset"表示此segment中起始消息的offset.

获取消息时,需要指定offset和最大chunk尺寸,offset用来表示消息的起始位置,chunk size用来表示最大获取消息的总长度(间接的表示消息的条数).根据offset,可以找到此消息所在segment文件,然后根据segment的最小offset取差值,得到它在file中的相对位置,直接读取输出即可。

                                   从磁盘原理理解文件读写优化_第9张图片

 

 

你可能感兴趣的:(kafka,磁盘,磁盘,kafka,文件碎片,随即读写,异步刷盘)