300行程式碼模擬cdn

2023-06-19 12:00:58

這一生聽過許多道理,但還是過不好這一生,這是因為缺少真正的動手實踐,光聽道理,缺少動手實踐的過程,學習難免會讓人覺得味同嚼蠟,所以我的分享都比較傾向於實踐,在一次次動手實踐的過程中感受知識原本純真的模樣。

大家好,我是藍胖子,往往從事網際網路開發的同學都聽過cdn這個詞,不過對於剛入行的同學可能會對這個概念比較模糊,今天我們就來聊聊它,並且我會在原理的基礎上在本地搭建一個cdn環境,模擬域名設定,回源,以及快取的過程。

本節原始碼已經上傳到github

https://github.com/HobbyBear/cdndemo

現在,讓我們開始吧。

cdn原理介紹

首先,我們來看下為什麼要用cdn,比如一個專注做視訊播放或者圖片閱覽的網站,當用戶瀏覽網站時,需要從網站拉取圖片或者視訊資源,這將產生流量費用,並且,如果使用者裡網站伺服器越遠,產生的流量費用將越高。而cdn的原理則是將視訊或者圖片資源快取在離使用者比較近的伺服器上,這樣既提升了響應速率,又節約了流量費。

來看下使用cdn後,使用者存取網站的過程。

如上圖所示,假設使用者自己的想要加速的域名是web.cdn.test,如果使用者想對這個域名進行加速,首先要去cdn服務商那裡設定上這個加速域名源站服務地址,接著cdn服務商會生成一個域名地址,這裡假設為web.cdn.test.c.lanpangzi,而使用者自己需要去自己的dns服務商那裡將加速域名web.cdn.test 指向這個新的域名地址,這種將一個域名指向另一個域名的記錄被稱作cname記錄。

經過上述步驟後,對域名web.cdn.test的存取會被指向web.cdn.test.c.lanpangzi,但目前還有一個問題,新的域名web.cdn.test.c.lanpangzi應該由cdn服務商自己的dns排程系統去解析,這樣cdn服務商才能將邊緣節點的ip返回給使用者,那本地dns伺服器怎麼知道web.cdn.test.c.lanpangzi這個域名要交給哪臺機器去解析呢?

原因是這樣的,cdn服務商在註冊自己的主域名時(這裡的主域名是langpangzi.) ,向dns伺服器註冊了一條ns記錄,ns記錄可以指定將某個域名的解析交給哪一臺dns伺服器解析,比如這裡,cdn服務商就把c.langpangzi. 域名的解析指向了cdn服務商自己的dns伺服器。

完成了這一步,使用者自己的加速域名最終就會被cdn服務商的dns伺服器去解析了,cdn服務商一般在全球各地都有自己的節點,所以它會根據使用者的ip去篩選一個離使用者比較近節點ip返回,這些節點被稱作邊緣節點 ,這樣使用者的請求就能就近存取了。

本地搭建一個cdn

我們把上面的請求過程與cdn架構在本地模擬下,把自己想象成一個cdn服務商,我們將會搭建cdn的域名排程中心,和邊緣節點,然後允許使用者提供加速域名和回源伺服器給我進行設定。

搭建dns伺服器

我們先來搭建一個dns伺服器,因為無論是cdn還是使用者本身都需要進行一些dns域名設定,你可以把當前這個dns伺服器想象成第三方dns運營商。

我們用dnsmasq在本地進行dns伺服器的搭建,我本地機器用的mac,安裝命令如下:

brew install  dnsmasq

==> Dependencies
Build: pkg-config ✔
==> Caveats
To start dnsmasq now and restart at startup:
  sudo brew services start dnsmasq
Or, if you don't want/need a background service you can just run:
  /opt/homebrew/opt/dnsmasq/sbin/dnsmasq --keep-in-foreground -C /opt/homebrew/etc/dnsmasq.conf -7 /opt/homebrew/etc/dnsmasq.d,*.conf
==> Analytics
install: 0 (30 days), 0 (90 days), 0 (365 days)
install-on-request: 0 (30 days), 0 (90 days), 0 (365 days

接著需要對其組態檔進行修改,設定上游伺服器,以及設定當前dns伺服器能夠解析的域名

從安裝的資訊可以看出,其組態檔是在/opt/homebrew/etc/dnsmasq.conf 這個位置,這裡我直接給出我的設定資訊

# 設定上行DNS,對應no-resolv
resolv-file=/Users/xiongchuanhong/dnsmasq.conf
# 執行程序以哪個使用者身份執行,直接用root,因為dnsmasq的設定涉及到許可權問題
user=root
# 設定dnsmqsq執行紀錄檔,對排錯很重要
log-facility=/Users/xiongchuanhong/logs/dnsmasq.log
# resolv.conf內的DNS定址嚴格按照從上到下順序執行,直到成功為止
strict-order
# DNS解析hosts時對應的hosts檔案,對應no-hosts
addn-hosts=/etc/hosts
cache-size=1024
# 多個IP用逗號分隔,192.168.x.x表示本機的ip地址,只有127.0.0.1的時候表示只有本機可以存取。
# 通過這個設定就可以實現同一區域網內的裝置,通過把網路DNS設定為本機IP從而實現區域網範圍內的DNS泛解析(注:無效IP有可能導至服務無法啟動)192.168.17.150 是我本地機器內網ip
listen-address=127.0.0.1,192.168.17.150
# 相當於ns記錄,c.lanpangzi的域名以及其子域名都會由本地1053埠的程序去進行解析
server=/c.lanpangzi/127.0.0.1#1053
# cname記錄,存取web.cdn.test 的域名都會指向web.cdn.test.c.lanpangzi 
cname=web.cdn.test,web.cdn.test.c.lanpangzi
# 重要!!這一行就是你想要泛解析的域名設定.
#address=/hello.me/127.0.0.1

上面resolv-file 所指向的檔案是要設定的上游dns伺服器,/Users/xiongchuanhong/dnsmasq.conf設定如下:

(base) ➜  ~ cat /Users/xiongchuanhong/dnsmasq.conf
 nameserver 8.8.8.8

當本地解析不了域名,那麼dnsmasq會詢問它的上游dns伺服器,所以我們把它設定成谷歌的域名解析系統。