天天看點

資料同步的一些思考與改進

閑的沒事,自己寫了個小網站,搭建在自己國外的VPS上,VPS記憶體極小(512M),而且還要跑點别的(你懂的),記憶體更緊張巴巴. 改造之前小網站用到了時髦的Redis,Rabbmitmq,Mysql,那時候阿裡雲的學生主機記憶體富足,裝這麼多中間件壓力不大,可到了這樣的小記憶體VPS上,一切都變得水土不服,索性啥中間件都不要了,資料庫也不要了.

沒了資料庫,網站的資料從哪裡來?存在哪裡? 文本形式持久化到本地磁盤?

國外的VPS不比國内,可能哪天說不能通路就不能通路了,VPS的磁盤存儲顯然不踏實.

同僚給我建議了萬能的Github,聽過Github托管代碼📜,托管靜态頁面🔮,托管女裝大佬💃,但托管網站資料倒是第一次聽說,于是我對網站架構進行了重新設計.

小網站資料不多,10M左右,所有資料直接加載到記憶體中伺服器也不會吃力,網站啟動,自動從Github Clone資料,并定期把記憶體中的資料序列化後Push到Github.

可以看到,整個過程中,好像沒有磁盤啥事了,在我的眼裡,Github就是一塊延時略高的磁盤(其實延時也還好,國外的Github通路速度飛快).

磁盤的讀取速度和記憶體無法比,何況遠端的Github,那麼如果減少資料從記憶體到Github的同步開銷呢?顯然就是減少同步的頻率.

一小時同步一次,應該夠了.

但如果我的網站在這一小時挂了boom🌋,而資料還沒來得及同步,那上次一同步到網站挂掉這個時間段内的資料不就沒了嗎?細思極恐😱!

既然一小時一次不安全,那就一分鐘同步一次!

其實這樣也是有問題的,小網站一般都是無人問津,如果以較高的頻率進行資料同步,可以說絕大多數(用網際網路的所法是百分之N個9)的資料同步都是沒意義的,同時還增大了資料的同步開銷,沒準Github還會把我的賬号給封了.

在我的網站中,有統一的資料通路層,隻要資料通路層中的insert,update,delete處加入資料同步事件,即可實作一旦更新立即同步.

這樣是資料是安全了,可是一次通路請求往往伴随着多次資料更新,每更新一次同步一次,可能是最腦殘🙈的做法吧.

資料更改一次同步一次不合理,同步頻率太低資料不安全,頻率太高多數同步沒有意義,到底該怎樣呢?

在揭開我的設計方案前,我們先來過一下CPU通路存儲器時所遵守的局部性原理.

在計算機存儲媒體這個金字塔中,越靠近金字塔頂端,空間越小,但是讀取資料越快;越靠近金字塔底端,空間越大,但通路速度也越慢.

正式因為這樣,是以每次自下而上的資料資料流大小逐層遞增, 交換頻率逐層遞減,如何在時間與空間上取到平衡點是關鍵.

于是有了空間局部性原理和時間局部性原理,力求讓計算機的資料流動更高效.

如果一條資料被通路,那麼與它臨近的資料也可能要被用到. 比如數組,你通路了索引1上的資料,那麼1附近的資料當然很有可能被通路,是以這個時候幹脆把1附近的資料也往上加載一個層級.

如果一條資料項正在被通路,那麼在近期它很可能還會被再次通路,是以這個時候幹脆就把它留在目前層級,先不急着回收掉.

而網站的資料的更新也是具有時間局部性的,像我這樣并冷門的網站,基本沒人通路,但是一旦通路了,立即就要進行點選量的更新,站點響應速度的記錄,沒準又會有評論留言,然後要通知管理者進行留言稽核.這大概就是不鳴則已,一鳴驚人,一次通路短期内往往立即觸發一連串的資料更新,我認為這也是一種時間局部性.

是以,在資料同步上,我設計了如下方案.

另起一個線程作為定時任務,主要負責定時資料同步

正常情況下,每小時與Github進行資料同步.

一旦網站資料被更新,檢查剩餘同步時間是否大于30秒.

** 如果大于三十秒,強行把計時器剩餘時間設定為30秒.

** 如果小于三十秒,不做操作.

計時器時間走完,立即同步資料到Github.

原本文章說到這裡就可以結束了,但程式員注定愛代碼愛過文字,又恰好我天生愛造輪子,我從令牌桶得到靈感設計了一個乞丐版沙<code>漏計時器</code>,可以用于任何定時任務的執行,班門弄斧,歡迎提出改進意見.

源碼位址: https://github.com/liuzhenyulive/iBlogs/blob/master/Src/iBlogs.Site.Core/Common/iBlogsTimer.cs

示範位址: https://www.iblogs.site