# 檔案 我們可能會需要產生圖片或檔案供使用者去下載,這些讓使用者可以公開存取檔案的原則大概有這些: - 隨機檔名 - 同一目錄下不要有太多檔案 - 資料庫僅儲存圖片檔名,不要紀錄完整路徑 - 使用 CDN 提高負載平衡及降低頻寬成本 # 隨機檔名 很多人可能會圖方便,讓檔案用可以猜出規則的方式做儲存,例如有人可能在儲存會員的照片,是用會員的編號當作圖片檔名,如果會員編號是整數的欄位,則就更容易讓人家猜出來,更方便地去解析你主機的所有會員照片,像是: ~~~ 100000001.png 100000002.png 100000003.png ... 100999999.png ~~~ 所以通常我們會將圖片的名稱依照會員編號的規則去做加密,我們可能可以用 md5 去做加密的動作,這樣圖片檔名可能會像是: ~~~ d69d3401d01a8ceed4549434e5ad9f40.png (`100000001` md5) 5a5ea04157ce4d020f65c3dd950f4fa3.png (`100000002` md5) 154666111ab87ce13405f384faeb5428.png (`100000003` md5) ... e0b50eb5c4add211417977e1f79364e0.png (`100999999` md5) ~~~ 這樣圖片的檔名看起來隨機了許多,比較不容易被猜出來,但是對比較厲害的人,可能會想要拿你的會員編號自己做 md5,所以還是可以看出規則,這時候我會試著在 md5 的會員編號字串加自定義的 salt 字串像是 `KeJyun`,這樣出來的圖片檔名會像這樣: ~~~ a3bce35e2b4e57911869b1bf5d040d71.png (`100000001KeJyun` md5) 5121a0fabb52c26c01817ee65df683a8.png (`100000002KeJyun` md5) 2ec12af8e6e011a0f5256b61db2145c3.png (`100000003KeJyun` md5) ... 467bd65bf6d4864adcc633caf2a70f7d.png (`100999999KeJyun` md5) ~~~ 這樣除非對方知道我們使用哪一個 salt 去做加密,否則就很難被猜出來 ### 同一目錄下不要有太多檔案 我們存放會員大頭照的路徑可能會像是: `http://www.kejyun.com/users/images/a3bce35e2b4e57911869b1bf5d040d71.png` 在上面的例子我們把所有的會員照片都存放在 `users/images` 的目錄下,對於系統程式,我們可以很快的指定路徑去讀取該檔案出來,但如果對於系統端的管理者,要去管理這些檔案時就會造成很大的困擾,想像你有 1000 萬個會員照片,所有的會員照片都放在同一個目錄下面,光是要使用 `ls`指令去列出那個目錄的所有照片,對於系統來說就是一大夢靨... 所以我們通常會對檔案做資料夾的分層處理,像是 `a3bce35e2b4e57911869b1bf5d040d71.png` 檔案,我們可能取其前 3 個字元 `a3b` 去做資料夾的分層,所以我們圖片會份在 `users/images/a3b/a3bce35e2b4e57911869b1bf5d040d71.png` 目錄下,分層資料夾的 3 個字元的[資料排列組合](3)為 `46,656` 種,所以若我們有 `1000 萬`個會員照片,我們可以預期照片會被平均的放在到各個分層資料夾,每個分層資料夾約 `214 張`照片 `(10000000 / 46625 = 214.33)`,這樣對於系統在做檔案的索引及瀏覽也會比較快。 資料夾的分層要如何分層,完全取決於你系統專案資料數量的需求,若你預期你的檔案會超過 1 億種,那麼分層方式我們可能會分成 2 層,依照上面規則,照片可能會被放到 `users/images/a3bc/e35/a3bce35e2b4e57911869b1bf5d040d71.png` 下面,要怎麼分層處理完全取決於你的需求狀況,沒有一定的規則! ### 資料庫僅儲存圖片檔名,不要紀錄完整路徑 我們的檔案可能會隨著系統使用人數變多,需要轉換成不同的管理方式,所以檔案在做大型專案時,很有可能會隨時被移動位置的,所以千萬不要將完整的圖片路徑存到資料表欄位中,否則以後在做檔案效能最佳化調校時,資料表檔案路徑還需要重新的異動更新,會是很大的難題,可能的瓶頸可能會卡在: - 專案不能只為了調整圖片路徑而關站維護 - 資料量很大,更新檔案路徑很慢,可能需要 3~7 天以上去更新資料表的資料 - 若更新失敗,或者是又需要重調整架構時,所耗費時間會更長 所以我們在資料表只要紀錄檔案的檔名就好,所有與架構有關的資料通通由程式去控制產生,程式只要改一下,檔案的存取架構隨時都可以容易的做異動 ### 使用 CDN 提高負載平衡及降低頻寬成本 我們的主機可能會使用 AWS、Linode 之類的雲端服務,這些的主機可能是放在日本或美國,我們希望使用者去距離使用者自己比較近的 CDN 主機,去存取這些不常被異動的靜態資料,這樣可以提高原本主機本身的負載流量,將流量做分散式的處理。 我們的圖片可能放在像是這樣的網址下: ~~~ http://cdn1.kejyun.com/users/images/a3bc/e35/a3bce35e2b4e57911869b1bf5d040d71.png http://cdn2.kejyun.com/users/images/a3bc/e35/a3bce35e2b4e57911869b1bf5d040d71.png http://cdn3.kejyun.com/users/images/a3bc/e35/a3bce35e2b4e57911869b1bf5d040d71.png ... http://cdn9.kejyun.com/users/images/a3bc/e35/a3bce35e2b4e57911869b1bf5d040d71.png ~~~ 這些不同的主機存放的圖片都與原主機的 `http://www.kejyun.com/users/images/a3bc/e35/a3bce35e2b4e57911869b1bf5d040d71.png` 相同,只是我們把同樣的靜態檔案分流複製到各個 CDN 主機上,這樣就不用讓原主機承載過高的頻寬吞吐量了! ### 參考網站 - [內容傳遞網路 CDN - Wiki](http://zh.wikipedia.org/wiki/%E5%85%A7%E5%AE%B9%E5%82%B3%E9%81%9E%E7%B6%B2%E8%B7%AF) - [CloudFlare](https://www.cloudflare.com/)