MiniCDN - 一個 Golang 實現的 CDN
一般來說會推薦采用qiniu或者upyun,又或者是amazon之類大公司的cdn服務,不過當需要一些自己實現的場景,比如企業內部軟件的加速,就需要一個私有的CDN了。
極簡內容分發系統是我在公司里面的一個項目,最近把他開源出來了。可能其他企業或者組織也需要一個類似的東西。
通常來說CDN分為push和pull兩種方式,push比較適合大文件,pull適合小一些的文件,但是使用起來比push要簡單的多。
MiniCDN采用的就是pull這種方式,目前的實現方式是所有緩存的文件存儲在內存中,使用LRU算法淘汰掉就的文件,鏡像的文件受限于緩沖區的大小(目前的緩沖區是512M),如果超過了這個緩沖器大小,就沒有加速的效果了。
沒有所有的智能DNS,直接用的是最簡單的http redirect. 還沒寫負載均衡, 所以redirect的時候,就是隨機返回一個節點(簡單粗暴)
MiniCDN分為manager和peer。都是寫在一個程序里。
我平常用的時候,就只開一個minicdn的Manager來加速我的后端服務器。如果沒有節點的話,manager就會把自己當成一個節點。然后當有特別大的下載即將要沖擊我的服務器的時候。我就會找很多的同事,將minicdn部署到他們平常用的電腦上(window系列, 因為是golang語言寫的,什么平臺的程序都能編譯的出來)。這樣我在短時間內就擁有了一個性能不錯的cdn集群(充分利用同事的資源)。當下載沖擊結束的時候,在把這些節點撤掉就可以了。相當省事
技術優勢
MiniCDN使用了谷歌開源出來的groupcache框架,目前dl.google.com后臺就用到了groupcache,性能而言遠超那些squid或者nginx-proxy-cache.
groupcache的數據獲取過程很有意思,我把他翻譯了過來
groupcache的運行過程
查找foo.txt的過程(節點#5 是N個節點中的一個,每個節點的代碼都是一樣的)
- 判斷foo.txt是否內存中,并且很熱門(super hot),如果在就直接使用它
- 判斷foo.txt是否在內存中,并且當前節點擁有它(譯者注:一致性hash查到該文件屬于節點#5),如果是就使用它
- 在所有的節點中, 如果foo.txt的擁有者是節點#5,就加載這個文件。如果其他請求(通過直接的,或者rpc請求),節點#5會阻塞該請求,直接加載完畢,然后給所有請求返回同樣的結果。否則使用rpc請求到擁有者的節點,如果請求失敗,就本地加載(譯者注:這種方式比較慢)
groupcache是2013年寫出來的,軟件也不怎么更新了。里面的HTTPPool還有兩個問題一直沒有修復,這兩個問題直接影響到節點之間不能交換數據。因為官方不用groupcache的這部分,所以連用戶提的issue都不修(真是蛋疼)
https://github.com/codeskyblue/groupcache 是我fork的,把這兩個問題修復了,雖然提了pr,不過感覺他們一時半會不會merge的。
受python-celery的啟發,我實現了peer退出時候的兩種狀態(Warm close and Code close). Warn close可以保證黨節點不在服務的時候才退出。Code close就是強制退出,下載者可能會發現下載中斷的問題。
架構
-
M: Manager
- 負責維護Peer的列表,每個peer會去Manager同步這個列表。
- 所有的請求會先請求到manager, 然后由manager重定向到不同的peer
-
P: Peer
- 提供文件的下載服務
- Peer之間會根據從manager拿到的peer列表,同步文件
Manager與Peer是一對多的關系
[M] |`------+--------+---...... | | | [P] [P] [P] ....
Installation
go get -u -v github.com/codeskyblue/minicdn # run minicdn -h
Requirements
- golang
- 使用golang前需要設置環境變量GOPATH, 通常export GOPATH=$HOME/goworkdir, 編譯后的文件會自動生成到$GOPATH/bin下
Run Manager
命令行啟動
./minicdn -mirror http://localhost:5000 -addr :11000 -log cdn.log
- 對網站http://localhost:5000進行鏡像加速
- 監聽11000端口
- 日志存儲在cdn.log中
源站的所有下載地址,最好都改成這個http://localhost:5000/something
Run Peer
命令行啟動
./minicdn -upstream http://localhost:11000 -addr :8001
- 指定Server地址http://localhost:11000
- 監聽8001端口
TODO
- token
- use a slave as a master
- request log
- cli args to specify cache size
CONTRIBUTING
開源軟件都會有一個這部分,感覺我也不能免俗。
- 代碼或README中的拼寫錯誤,都是可以提Pull request的。
- 如果有什么大的改動,請先提issue進行討論。
- 代碼使用golang默認的fmt
Tests
go test -v