有批流量好便宜啊 需要的話就自己架CDN囉
如何自己做CDN
2022 Oct 30 技術筆記
Google 的 VPS 雖然好用
但 Google 的頻寬好貴啊
如果網站常常要開大量的圖
費用就會噴很快
怎麼辦呢?
起源
之前為了節省頻寬費
用了一個叫做 TinifyCDN 的服務
TinifyCDN 很厲害
他原本主要服務是 tinyjpg/tintpng
是壓縮圖片的網路服務
可以把圖片壓縮到 20%
就可以節省頻寬
後來他推出一個把 CDN 跟壓縮圖片綁在一起的服務
既可以CDN 又可以壓縮圖片
但...
服務還是小貴
重點是他有綁網域數量
所以不是很好用
就想說這類的服務是不是可以自己弄一個?
什麼是CDN
這是一個很大的問題但 Google 可以回答你很多問題
所以我就隨便講講
基本上 CDN 是拿來分散頻寬的工具
如果你的使用者在世界各地
你的伺服器只有一台
理論上離你伺服器較多節點的客戶
開網站會比較慢
但網頁是由 html/css/圖片 等元素組成
css/js/圖片 基本上是不太會改變的
如果把這些素材 架設在世界各地的主機
不管客戶在哪裡
開啟頁面的速度也會加快(一點點)
另外就是可以把主機流量降低
如果素材的流量分散到其他比較便宜的流量
那網站營運成本也會降低
初始想法
我有租一台 Linode因為有些客戶用 WordPress
CPU/RAM 吃很兇
我只好把這些客戶放在 Linode
因為這台我沒有裝 CloudLinux
就讓他們在這台搶資源
但他們頻寬/流量用的不多
Linode 在開圖/頻寬方面還算優秀
如果我可以把 Google 的頻寬用量導到 Linode
不就可以省一筆錢?
於是我開始研究 TinifyCDN 是怎麼做的
TinifyCDN 的做法是把你的圖片 host 改掉
例如假設這張圖
路徑是
https://lupopi.com/images/upload_file/1/bc1d7d63806dcc49aba3d859a627378ec7592b3d.jpeg
如果套用 TinifyCDN 的服務
會變成
https://12345678.tinifycdn.com/images/upload_file/1/bc1d7d63806dcc49aba3d859a627378ec7592b3d.jpeg
12345678.tinifycdn.com 是 TinifyCDN
而 12345678 是 TinifyCDN 隨便給你的一個子網域
每個網站會不一樣
於是開圖的時候 圖片的流量就會被導到 TinifyCDN
TinifyCDN 那邊除了抓原始圖 還會幫你壓縮圖片
第一次開圖會稍微卡一下 (因為壓縮要一點時間)
第二次開圖以後就是快取 就會變很快
實作
做起來沒有很難就是把圖片用另一台伺服器開而已
CDN的機器上表面上是一張圖片
但透過 rewrite 是去開一個 php 程式
程式會去判斷 CDN 機器上是否有圖
有圖的話直接輸出圖片
沒圖的話要去原本網站抓
因為 12345678.tinifycdn.com 是 TinifyCDN 給的
TinifyCDN 自然知道原本對應的網站是誰
就會去原網站抓圖
所以不用一個下午就做好了
但問題也隨之而來
陷阱
原始網站上如何把圖片的連結都轉成 CDN 的網域?有兩種做法
1. 用外掛(WP) 或是改寫程式
把產生圖片的連結改掉
2. 如果沒辦法改程式
就寫 rewrite 把圖片路徑都導到 CDN 路徑
因為有可能不是所有圖片都是程式產生的
如果要做到完全把圖片流量導到 CDN
會用混合方法
也就是 1 跟 2 並用
但併用的時候就會出一個問題
當 CDN 沒圖的時候
會去原始主機抓圖
抓圖的時候 又會被 2 的 rewrite 重導到 CDN
抓圖的程式就會無限迴圈 然後掛掉
解決方法就是把 CDN 的爬蟲的 Agent 取名字
然後再 2 的 重導 加入判斷 Agent 名字的條件
如果是 Agent 來抓圖 不要 重導 回 CDN
效能問題
當一切看起來很順利的時候突然網站的圖都打不開了
短時間內只能CDN機器的 Apache restart
但是一直 restart 也不是問題
一開始還以為是 Linode 機器不給力
因為現在 VPS 都有所謂 dedicated/shared CPU 的差別
dedicated CPU 不用跟人家共用 CPU
但比較貴
早期我們都租 shared CPU
想說應該是鄰居搶資源 所以圖片開不起來
於是直接升級主機 想說花錢解決
過了一陣子還是掛掉
想想應該是 php 的問提
因為每張圖不管要不要抓圖
都要透過 php 處理
叫一隻 php 起來除了吃記憶體還要吃 CPU
卡住好像也是應該的
後來不小心查到有人寫過類似的東西
他是用 nginx + php 寫的
參考了一下相關設定
似乎是 CDN 有快取檔的情況下
直接從 nginx 就吐圖出去了
不需要經過 php
所以快很多
但難就難在 rewrite 怎麼寫
花了週末的一天終於摸索出來
大概分成兩個步驟
1. 先把主機端的 URL 分成來源跟要求的路徑
用 12345678 去查看是哪個網站 (我是直接用網域去對應快取檔案的目錄)
rewrite 的新路徑如果有圖 就開圖
這步驟不需要經過 php
由 apache 處理
2. 如果404
就走下一個 rewrite 到 index.php (隨便一隻固定的 php 程式即可)
程式會抓圖/存起來 (要不要跑壓縮就看你自己)
然後吐圖
加強版
沒問題以後就可以弄加強版如果來源是 js/css 可以跑對應的 minify
這部分上網找 有一堆可以應用
應該是不用自己寫
如果來源是圖片
可以套 shortpixel
shortpixel 很慢
但便宜
線上直接呼叫 API 可能要很久
(實驗過一張圖平均要花20秒)
所以可以用背景定時壓圖
如果要更快更省錢
可以丟 Linode 的 Storage 或是 DigitalOcean 的 Space 服務
這兩個都是類似 Amazon 的 S3 服務
非常便宜
起始價 10U/月
但有 1T/月 流量
DigitalOcean 的 Space 更是真的有串 CDN
可以把素材擴散到全世界的主機
參考資源
韓國人自幹CDNhttps://github.com/marshallku/Simple-CDN
rewrite 寫法參考
https://stackoverflow.com/questions/6297963/htaccess-check-if-a-file-exists-based-on-variables
0則留言