<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 背景:Punch hole和Sparse file Punch hole是一個需要操作系統和文件系統支持的特性,顧名思義就是在文件中打洞。這個特性的目的是為了減少數據文件的磁盤開銷。比如一個大文件中有一部分數據我們是不需要的,就可以通過punch hole特性將其刪除,相當于在文件中打了個洞,這個洞是不占用磁盤的。 Punch hole特性通過fallocate調用來實現,在其第二個參數指定flag FALLOC_FL_PUNCH_HOLE時,第三個參數指定需要punch hole的偏移位置,第四個參數指定punch hole的長度。當成功打洞后,以后訪問到這個范圍的數據都返回0。 fallocate的描述見[文檔](http://www.man7.org/linux/man-pages/man2/fallocate.2.html)。根據文檔的描述,`FALLOC_FL_PUNCH_HOLE`?需要和另外一個flag?`FALLOC_FL_KEEP_SIZE`一起使用,也就是說,即使在文件中打洞,通過stat獲得的文件大小也不會發生變化,你需要通過du命令來獲得準確的磁盤文件大小。 目前不是所有的內核都支持該特性,在阿里環境需要使用rh6 2.6.32-358及之后的版本,另外由于對應的flag 宏沒有定義,我們需要顯式的定義如下兩個宏:(感謝 @伯瑜 大神的指點) ~~~ #define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ #define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ ~~~ 通常情況下,偏移量和長度要求是文件系統的block size大小,否則fallocate調用可能失敗并返回EINVAL。 除了上面這兩個flag外,還有另外一個比較有意思的flag:`FALLOC_FL_COLLAPSE_RANGE`,名字和其功能比較形象,相當于在挖洞后,這個洞并沒有留下,而是把后面的數據往前面移,因此被打洞的部分,在被隨后訪問到時,讀取到的數據就不是0,而是后面的數據。 關于這個flag可以參考[這篇文章](http://lwn.net/Articles/589260/)了解其背景。 文件的管理使用sparse file(稀疏文件),一般支持punch hole特性的,都會支持sparse file,對于sparse file,可以參閱這篇[博客](http://m.blog.csdn.net/blog/changyanmanman/8760033),講的非常詳細。簡單的重整了下博客中的配圖,如下所示: ![sparse file](https://box.kancloud.cn/2015-09-24_56039bf586e78.png "sparse file") 然而需要注意一種情況,由于文件中的空洞不占磁盤空間,當磁盤接近滿時,如果向空洞寫入數據,就可能觸發寫入失敗的問題,導致不可預料的問題,因此空余的磁盤空間閥值需要多預留點。 ## InnoDB 新壓縮實現 MySQL 5.7.8版本實現了一種新的壓縮方式([WL#7696](http://dev.mysql.com/worklog/task/?id=7696)),也就是所謂的Innodb Transaparent PageIO Compression,其原理很簡單,就是利用punch hole + 數據壓縮來實現的。其在內存中表現的是一個正常的page,只在讀寫到磁盤時,才進行文件壓縮、解壓處理。處理邏輯如下圖所示: ![innodb punch](https://box.kancloud.cn/2015-09-24_56039bf5e1ce3.png "innodb punch") 首先,InnoDB增加了新的Page類型,這意味著如果使用該特性,則不能原地降級到老版本,需要對格式進行轉換才能降級。 目前上游支持兩種壓縮算法:zllib及lz4,但我們也可以很方便的進行擴展新的算法。 被壓縮的數據包含除FIL_PAGE_DATA之外的所有數據(包括tailer),但需要以block size對齊(線上環境的block size通常為4KB),這意味著即使我們把數據從16KB壓縮到9KB,也需要存儲12KB的數據。因此block size設小點,這樣的場景將受益,可以減少空間浪費。 ## 表定義 首先需要操作系統支持該特性,在阿里的環境里,需要裝上新版內核(如上述)讓系統支持punch hole。 可以通過CREATE TABLE 或ALTER TABLE 來定義壓縮表: ~~~ mysql> create table sb1 (a int, b blob) compression='zlib'; Query OK, 0 rows affected (0.05 sec) ~~~ 也可以選擇compression=’lz4’來指定lz4壓縮算法;注意對compression屬性的ALTER是立刻生效的,因此在做完ALTER COMPRESSION屬性操作后,需要做一次表的rebuild,例如optimize table操作,才能對已有的數據做punch hole。 compression屬性存儲在frm文件中,以兩個字節存儲字符串長度,隨后存儲compression屬性定義字符串,這也是一個操作系統降級的風險點。 具體的使用參閱[官方文檔](http://dev.mysql.com/doc/refman/5.7/en/innodb-page-compression.html)。 ## 相關代碼邏輯 壓縮數據 壓縮數據發生在對磁盤進行IO WRITE之前: 1. 先在內存中壓縮數據,并對齊Block size,確定做punch hole的范圍,同時將即將寫入文件的buf地址指向新分配的壓縮頁地址(這里存在優化的空間,需要避免重復分配內存塊)。參考函數: * Native AIO: AIO::reserve_slot –> os_file_compress_page * 同步寫:os_file_pwrite –> os_file_io –> os_file_compress_page 2. 將壓縮處理過的page寫入文件; 3. 隨后調用函數os_file_io_complete中,執行punch hole操作(os_file_punch_hole)。 解壓數據 在從磁盤讀取數據到磁盤后,首先要進行解壓:參考函數:os_file_io_complete –> os_file_decompress_page 特殊處理 1. 通過dblwr恢復的corruption的page寫入時禁止壓縮模式,因為此時innodb處于恢復模式,還沒拿到server層存儲的compression屬性; 2. row_merge_read 和row_merge_write,一般是用于排序的臨時文件,無需做壓縮/解壓; 3. truncate操作的文件日志禁止壓縮模式。 代碼整體的邏輯比較清晰,但改動點還比較多,后續我們將該特性Port到RDS版本,結合新內核來發揮數據空間節省的目的。 最后,Facebook的大神Domas寫了一篇[博客](http://dom.as/2015/04/09/how-innodb-lost-its-advantage/),認為InnoDB推出這樣的壓縮特性,使其正在喪失自身的優勢,非常值得一讀。簡單的摘要下: * 無法完美壓縮:例如9KB的數據可能需要12kb來存儲,取決于block size; * 無法壓縮Buffer pool, 這是和傳統innodb壓縮相比,以前的壓縮方式可以在內存中只存放壓縮頁拷貝 (然而也有可能同時存在壓縮和解壓頁),因此用戶可能需要去購買iops更高的設備,而oracle正好也賣這些…. * punch hole 可能產生的文件碎片化,底層的文件管理更加復雜; * 對innodb文件做punch hole可能帶來的后果是,使得每個文件的page變成一個獨立的segment,文件系統需要單獨的journal和metadata來管理。另外也有可能有性能問題:可能比non-sparse的寫操作昂貴五倍 (這依賴于具體的內核); * 刪除一個擁有幾百萬個段管理對象的數據文件帶來的開銷會非常昂貴。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看