成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用Go實(shí)現(xiàn)Redis之五持久化

ybak / 3482人閱讀

摘要:數(shù)據(jù)持久化到磁盤在的編碼中沒有使用類似的事件循環(huán),我們在此依賴字段作為標(biāo)識。變化即為持久化的時機(jī)。服務(wù)啟動加載數(shù)據(jù)持久化數(shù)據(jù)從文件加載進(jìn)內(nèi)存的方式是模擬客戶端執(zhí)行命令,逐條將文件命令發(fā)送給服務(wù)端。

寫在前面

本文實(shí)現(xiàn)的Godis代碼版本為:v0.1

Redis持久化方式 RDB持久化

BGSAVE和SAVE命令生成RDB文件,存儲數(shù)據(jù)庫信息。當(dāng)服務(wù)器啟動,RDB文件也會作為原始數(shù)據(jù),加載近服務(wù)內(nèi)存。這里存在一個優(yōu)先級問題——當(dāng)AOF持久化是打開狀態(tài),優(yōu)先從AOF文件加載數(shù)據(jù)、還原數(shù)據(jù)庫狀態(tài)。

SAVE命令會阻塞服務(wù),而BGSAVE派生獨(dú)立進(jìn)程,不會阻塞。同時可以通過選項(xiàng)配置自動執(zhí)行RDB持久化的周期。

Redis服務(wù)端通過記錄幾個參數(shù)(如第一篇提到的server.dirty字段記錄了上一次SAVE后經(jīng)歷了多少次數(shù)據(jù)庫修改)維護(hù)數(shù)據(jù)庫的修改情況。當(dāng)周期性的后臺操作serverCon執(zhí)行時,會檢查數(shù)據(jù)庫的更新狀態(tài)是否滿足RDB持久化條件,依此保存數(shù)據(jù)庫狀態(tài)。
注意:RDB的文件對數(shù)據(jù)庫數(shù)據(jù)的存儲,采用的方式是存儲鍵值對。

AOF持久化

前文提到RDB文件保存的是數(shù)據(jù)本身,而AOF文件存儲的是執(zhí)行的命令轉(zhuǎn)成的協(xié)議??梢酝ㄟ^開啟Redis的AOF持久化,操作若干命令后,查看appendonly.aof文件了解。
因?yàn)槭菍?shù)據(jù)的備份操作,讀命令無需記錄,只需記錄修改型操作。

如果AOF持久化對每次修改命令都計(jì)入文件,會多記錄一些無效命令。如:

set alpha 123
set alpha 1
set alpha 321
set alpha 123

四條命令是過程,數(shù)據(jù)庫記錄的最終值123才是過程的最終結(jié)果。
為了避免對同一個key的操作的“無效命令”的記錄,Redis有AOF重寫機(jī)制——讀取當(dāng)前數(shù)據(jù)狀態(tài)作為AOF文件要追加的命令記錄。

Godis實(shí)現(xiàn)AOF持久化

Godis只實(shí)現(xiàn)AOF持久化,并且不對命令進(jìn)行重寫歸并操作,所有修改操作都會記錄進(jìn)AOF文件。這也意味著,在數(shù)據(jù)保存階段,會有很多無效I/O操作;加載階段,會有很多無效的命令被執(zhí)行。

數(shù)據(jù)持久化到磁盤

在Godis的編碼中沒有使用Redis類似的事件循環(huán),我們在此依賴server.dirty字段作為標(biāo)識。dirty變化即為持久化的時機(jī)。

首先,在命令調(diào)用處添加AOF持久化判斷,如果dirty變化,則進(jìn)行持久化:

func call(c *Client, s *Server) {
    dirty := s.Dirty
    c.Cmd.Proc(c, s)
    dirty = s.Dirty - dirty
    if dirty > 0 {//dirty變化 進(jìn)行持久化
        AppendToFile(s.AofFilename, c.QueryBuf)
    }

}

執(zhí)行持久化操作的函數(shù)AppendToFile也很簡單,對文件追加寫,并且即刻關(guān)閉:

func AppendToFile(fileName string, content string) error {
    // 以只寫的模式,打開文件
    f, err := os.OpenFile(fileName, os.O_WRONLY|syscall.O_CREAT, 0644)
    if err != nil {
        log.Println("log file open failed" + err.Error())
    } else {
        n, _ := f.Seek(0, os.SEEK_END)
        _, err = f.WriteAt([]byte(content), n)
    }
    defer f.Close()
    return err
}

最后,在修改型命令(如set命令)的實(shí)現(xiàn)處,添加對server.dirty的更新。

func SetCommand(c *Client, s *Server) {
    ···
    s.Dirty++
    ···
}

我們來測試下效果,重新編譯godis-server.go,并執(zhí)行set alpha 123

已經(jīng)成功在文件中寫入了命令協(xié)議。

服務(wù)啟動加載數(shù)據(jù)

持久化數(shù)據(jù)從文件加載進(jìn)內(nèi)存的方式是模擬客戶端執(zhí)行命令,逐條將AOF文件命令發(fā)送給服務(wù)端。

func LoadData() {
    c := godis.CreateClient()
    pros := core.ReadAof(godis.AofFilename)
    for _, v := range pros {
        c.QueryBuf = string(v)
        err := c.ProcessInputBuffer()
        if err != nil {
            log.Println("ProcessInputBuffer err", err)
        }
        godis.ProcessCommand(c)
    }
}

core.ReadAof將AOF文件讀入內(nèi)存,分條存儲。而后的ProcessCommand在set/get命令實(shí)現(xiàn)處有介紹,不再說明。

集成測試

關(guān)閉服務(wù)端,重新啟動服務(wù)端,直接在客戶端執(zhí)行get alpha,查看是否能獲取之前set的值:

查驗(yàn)AOF文件,沒有讀命令get相關(guān)的記錄。

本篇問題

偽客戶端執(zhí)行時不要執(zhí)行持久化操作,對Client結(jié)構(gòu)增加偽終端標(biāo)志位,用于持久化判斷:

func LoadData() {
    c := godis.CreateClient()
    c.FakeFlag = true
    ···
}
小結(jié)

沒有下集預(yù)告了。
這五篇短文的初衷是記錄在學(xué)習(xí)GO時寫的小demo,結(jié)果花在其他語言之前的精力超出了預(yù)算,所以在那以后也沒有再繼續(xù)開發(fā)Godis的新feature。

明天在公司的工作迎來忙碌的項(xiàng)目改造期,趁著今天端午小長假最后一天,了解了V0.1版本。
不過,在不久的將來,也許下個小長假,會將前文提到過的key過期、網(wǎng)絡(luò)優(yōu)化、API開發(fā)、Stream等新的feature和優(yōu)化公之于眾。
歡迎討論。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28879.html

相關(guān)文章

  • Go實(shí)現(xiàn)Redis之一準(zhǔn)備工作

    摘要:命令實(shí)現(xiàn)命令是最常用的命令之一,也是最能反映緩存發(fā)展歷史的操作。命令在客戶端接收之后,經(jīng)由協(xié)議轉(zhuǎn)換傳遞給服務(wù)端執(zhí)行。服務(wù)端執(zhí)行命令前先查詢是否支持該命令,以決定是否執(zhí)行。,是的簡稱,代表的是只存增量的持久化方式。 緣起 最近公司的第一個PHP轉(zhuǎn)GO項(xiàng)目已經(jīng)在生產(chǎn)環(huán)境穩(wěn)定運(yùn)行數(shù)周,又逢需求小年兒,最近可以得空分享下去年學(xué)GO過程中的練手項(xiàng)目Godis——用Golang實(shí)現(xiàn)的Redis. ...

    zhangke3016 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<