亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go存儲基礎使用direct io方法實例

 更新時間:2023年12月01日 09:50:14   作者:qiya  
這篇文章主要介紹了Go存儲基礎之如何使用direct io方法實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

Go 存儲編程怎么使用 O_DIRECT 模式?

今天分享一個存儲細節(jié),Go 存儲編程怎么使用 O_DIRECT 模式?

之前提過很多次,操作系統(tǒng)的 IO 過文件系統(tǒng)的時候,默認是會使用到 page cache,并且采用的是 write back 的方式,系統(tǒng)異步刷盤的。由于是異步的,如果在數(shù)據(jù)還未刷盤之前,掉電的話就會導致數(shù)據(jù)丟失。

如果想要明確數(shù)據(jù)寫到磁盤有兩種方式:要么就每次寫完主動 sync 一把,要么就使用 direct io 的方式,指明每一筆 io 數(shù)據(jù)都要寫到磁盤才返回。

那么在 Go 里面怎么使用 direct io 呢?

有同學可能會說,那還不簡單,open 文件的時候 flag 用 O_DIRECT 嘛,然后。。。

是嗎?有這么簡單嗎?

提兩個問題,童鞋們可以先思考下:

  • O_DIRECT 這個定義在 Go 標準庫的哪個文件?
  • direct io 需要 io 大小和偏移扇區(qū)對齊,且還要滿足內存 buffer 地址的對齊,這個怎么做到?

O_DIRECT 的知識點

在此之前,先回顧 O_DIRECT 相關的知識。direct io 也就是常說的 DIO,是在 Open 的時候通過 flag 來指定 O_DIRECT 參數(shù),之后的數(shù)據(jù)的 write/read 都是繞過 page cache,直接和磁盤操作,從而避免了掉電丟數(shù)據(jù)的尷尬局面,同時也讓應用層可以自己決定內存的使用(避免不必要的 cache 消耗)。

direct io 一般解決兩個問題:

  • 數(shù)據(jù)落盤,確保掉電不丟失;
  • 減少內核 page cache 的內存使用,業(yè)務層自己控制內存,更加靈活;

direct io 模式需要用戶保證對齊規(guī)則,否則 IO 會報錯,有 3 個需要對齊的規(guī)則:

  • IO 的大小必須扇區(qū)大?。?12字節(jié))對齊
  • IO 偏移按照扇區(qū)大小對齊;
  • 內存 buffer 的地址也必須是扇區(qū)對齊;

思考標題

為什么 Go 的 O_DIRECT 知識點值得一提?

以下按照兩層意思分析思考。

第一層意思:O_DIRECT 平臺不兼容

劃重點:Go 標準庫 os 中的是沒有 O_DIRECT 這個參數(shù)的。

為什么呢?

Go os 庫實現(xiàn)的是各個操作系統(tǒng)兼容的實現(xiàn),direct io 這個在不同的操作系統(tǒng)下實現(xiàn)形態(tài)不一樣。其實 O_DIRECT 這個 Open flag 參數(shù)本就是只存在于 linux 系統(tǒng)。

以下才是各個平臺兼容的 Open 參數(shù) ( os/file.go )。

const (
   // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
   O_RDONLY int = syscall.O_RDONLY // open the file read-only.
   O_WRONLY int = syscall.O_WRONLY // open the file write-only.
   O_RDWR   int = syscall.O_RDWR   // open the file read-write.
   // The remaining values may be or'ed in to control behavior.
   O_APPEND int = syscall.O_APPEND // append data to the file when writing.
   O_CREATE int = syscall.O_CREAT  // create a new file if none exists.
   O_EXCL   int = syscall.O_EXCL   // used with O_CREATE, file must not exist.
   O_SYNC   int = syscall.O_SYNC   // open for synchronous I/O.
   O_TRUNC  int = syscall.O_TRUNC  // truncate regular writable file when opened.
)

發(fā)現(xiàn)了嗎?O_DIRECT 根本不在其中。O_DIRECT 其實是和系統(tǒng)平臺強相關的一個參數(shù)。

問題來了,那么 O_DIRECT 定義在那里?

跟操作系統(tǒng)強相關的自然是定義在 syscall 庫中:

// syscall/zerrors_linux_amd64.go
const (
    // ...
 O_DIRECT                         = 0x4000
)

怎么打開文件呢?

// +build linux
// 指明在 linux 平臺系統(tǒng)編譯
fp := os.OpenFile(name, syscall.O_DIRECT|flag, perm)

第二層意思:Go 無法精確控制內存分配地址

標準庫或者內置函數(shù)沒有提供讓你分配對齊內存的函數(shù)。

direct io 必須要滿足 3 種對齊規(guī)則:io 偏移扇區(qū)對齊,長度扇區(qū)對齊,內存 buffer 地址扇區(qū)對齊。前兩個還比較好滿足,但是分配的內存地址作為一個小程序員無法精確控制。

先對比回憶下 c 語言,libc 庫是調用 posix_memalign 直接分配出符合要求的內存塊。go 里面怎么做?

先問個問題:Go 里面怎么分配 buffer 內存?

io 的 buffer 其實就是字節(jié)數(shù)組嘛,很好回答,最常見自然是用 make 來分配,如下:

buffer := make([]byte, 4096)

那這個地址是對齊的嗎?

答案是:不確定。

那怎么才能獲取到對齊的地址呢?

劃重點:方法很簡單,就是先分配一個比預期要大的內存塊,然后在這個內存塊里找對齊位置。 這是一個任何語言皆通用的方法,在 Go 里也是可用的。

什么意思?

比如,我現(xiàn)在需要一個 4096 大小的內存塊,要求地址按照 512 對齊,可以這樣做:

  • 先分配要給 4096 + 512 大小的內存塊,假設得到的地址是 p1 ;
  • 然后在 [ p1, p1+512 ] 這個地址范圍找,一定能找到 512 對齊的地址(這個能理解嗎?),假設這個地址是 p2 ;
  • 返回 p2 這個地址給用戶使用,用戶能正常使用 [ p2, p2 + 4096 ] 這個范圍的內存塊而不越界;

以上就是基本原理了,童鞋理解了不?下面看下代碼怎么寫。

const (
    AlignSize = 512
)
// 在 block 這個字節(jié)數(shù)組首地址,往后找,找到符合 AlignSize 對齊的地址,并返回
// 這里用到位操作,速度很快;
func alignment(block []byte, AlignSize int) int {
   return int(uintptr(unsafe.Pointer(&block[0])) & uintptr(AlignSize-1))
}
// 分配 BlockSize 大小的內存塊
// 地址按照 512 對齊
func AlignedBlock(BlockSize int) []byte {
   // 分配一個,分配大小比實際需要的稍大
   block := make([]byte, BlockSize+AlignSize)
   // 計算這個 block 內存塊往后多少偏移,地址才能對齊到 512 
   a := alignment(block, AlignSize)
   offset := 0
   if a != 0 {
      offset = AlignSize - a
   }
   // 偏移指定位置,生成一個新的 block,這個 block 將滿足地址對齊 512;
   block = block[offset : offset+BlockSize]
   if BlockSize != 0 {
      // 最后做一次校驗 
      a = alignment(block, AlignSize)
      if a != 0 {
         log.Fatal("Failed to align block")
      }
   }
   return block
}

所以,通過以上 AlignedBlock 函數(shù)分配出來的內存一定是 512 地址對齊的。

有啥缺點嗎?

浪費空間嘛。 命名需要 4k 內存,實際分配了 4k+512 。

我太懶了,一行代碼都不愿多寫,有開源的庫嗎?

還真有,推薦個:https://github.com/ncw/directio ,內部實現(xiàn)極其簡單,就是上面的一樣。

使用姿勢很簡單:

步驟一:O_DIRECT 模式打開文件:

// 創(chuàng)建句柄
fp, err := directio.OpenFile(file, os.O_RDONLY, 0666)

封裝關鍵在于:O_DIRECT 是從 syscall 庫獲取的。

步驟二:讀數(shù)據(jù)

// 創(chuàng)建地址按照 4k 對齊的內存塊
buffer := directio.AlignedBlock(directio.BlockSize)
// 把文件數(shù)據(jù)讀到內存塊中
_, err := io.ReadFull(fp, buffer)

關鍵在于:buffer 必須是特制的 [ ]byte 數(shù)組,而不能僅僅根據(jù) make([ ]byte, 512 ) 這樣去創(chuàng)建,因為僅僅是 make 無法保證地址對齊。

總結

  • direct io 必須滿足 io 大小,偏移,內存 buffer 地址三者都扇區(qū)對齊;
  • O_DIRECT 不在 os 庫,而在于操作系統(tǒng)相關的 syscall 庫;
  • Go 中無法直接使用 make 來分配對齊內存,一般的做法是分配一塊大一點的內存,然后在里面找到對齊的地址即可;

以上就是Go存儲基礎使用direct io方法實例的詳細內容,更多關于Go存儲direct io 的資料請關注腳本之家其它相關文章!

相關文章

  • Go并發(fā)編程之sync.Once使用實例詳解

    Go并發(fā)編程之sync.Once使用實例詳解

    sync.Once使用起來很簡單, 下面是一個簡單的使用案例,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-11-11
  • 在Go語言開發(fā)中實現(xiàn)高性能的分布式日志收集的方法

    在Go語言開發(fā)中實現(xiàn)高性能的分布式日志收集的方法

    本文介紹了在Go語言開發(fā)中實現(xiàn)高性能分布式日志收集的關鍵步驟和考慮因素,包括日志生成與采集、日志傳輸、日志收集器的高性能網(wǎng)絡I/O、日志存儲與分析、監(jiān)控與告警系統(tǒng)、擴展性與可維護性等方面,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2025-01-01
  • 一文帶你學會使用Go語言實現(xiàn)自己的MCP服務端

    一文帶你學會使用Go語言實現(xiàn)自己的MCP服務端

    這篇文章將帶大家速覽MCP的核心概念,并以Go語言為例,介紹如何開發(fā)MCP服務端和客戶端,文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下
    2025-04-04
  • Go語言中時間time相關處理方法詳解

    Go語言中時間time相關處理方法詳解

    在Go語言中,time?包是處理時間和日期的核心,它提供了豐富的函數(shù)和方法,用于顯示、測量、計算、格式化、解析時間等,本文給大家詳細介紹了Go時間time相關處理方法的相關資料,需要的朋友可以參考下
    2024-10-10
  • go mayfly開源項目代碼結構設計

    go mayfly開源項目代碼結構設計

    這篇文章主要為大家介紹了go mayfly開源項目代碼結構設計詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • 詳解Go語言中泛型的實現(xiàn)原理與使用

    詳解Go語言中泛型的實現(xiàn)原理與使用

    本文是對泛型的基本思想及其在?Go?中的實現(xiàn)的一個比較容易理解的介紹,同時也是對圍繞泛型的各種性能討論的簡單總結,感興趣的可以學習一下
    2022-05-05
  • Go安裝和環(huán)境配置圖文教程

    Go安裝和環(huán)境配置圖文教程

    本文主要介紹了Go安裝和環(huán)境配置圖文教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • Go語言調用SiliconFlow實現(xiàn)文本轉換為MP3格式

    Go語言調用SiliconFlow實現(xiàn)文本轉換為MP3格式

    這篇文章主要為大家詳細介紹了Go語言如何調用?SiliconFlow?語音生成?API?的腳本,用于將文本轉換為?MP3?格式的語音文件,感興趣的小伙伴可以了解下
    2025-02-02
  • 一文詳解Golang中的切片數(shù)據(jù)類型

    一文詳解Golang中的切片數(shù)據(jù)類型

    這篇文章主要介紹了一文詳解Golang中的切片數(shù)據(jù)類型,切片是一個種特殊的數(shù)組。是對數(shù)組的一個連續(xù)片段的引用,所以切片是一個引用類型
    2022-09-09
  • Golang開發(fā)命令行之flag包的使用方法

    Golang開發(fā)命令行之flag包的使用方法

    這篇文章主要介紹Golang開發(fā)命令行及flag包的使用方法,日常命令行操作,相對應的眾多命令行工具是提高生產(chǎn)力的必備工具,本文圍繞該內容展開話題,需要的朋友可以參考一下
    2021-10-10

最新評論