2016年10月24日 星期一

Apache Traffic Server & Varnish Cache 之我見. (Part 2)

上一篇忘了講,大部分的人弄 proxy,架構應該都是像下面這樣弄的:




















流量由 l4 load balancer 導入,可能用 round robin 或者是一般的 hash 將流量散到各台去,這樣會有幾個問題可能發生:

  1. 如果是 round robin,任意一個 url 都可能導到任意一台,假設我有 100 台 storage,如果很不幸的每次都是導到沒有 cache 的某台 storage,這樣對 Origin Server 就是一百次的 request,並沒有真的解決問題。
  2. 如果是用一般的 hash,全部的機器都健康的時候,hash 都維持得很好,cache hit 也可能都會不低,但是一但某台機器掛點,會重新 re hash,原本養的 cache 全都報銷了。
再講回 Apache Traffic Server,其實它源自 Inktomi 的 proxy server,設計精良,當年被 yahoo 併購之後,yahoo 只看到 inktomi 的搜尋部分業務,其他的東西都被冷凍起來,後來有人挖寶之後,發現了 inktomi proxy server,一用之後驚為天人,轉身變成 Yahoo Traffic Server,並且大量部署在 yahoo cdn 上。

不過後來可能因為政策改變,yahoo 內部自行研發了 uff 這套原本想要取代 yts 的 proxy server,所以將 Yahoo Traffic Server 在 2009 年捐給 Apache Project,原本一些在內部做 yts 研發的人員,大部分也同時成為 apache committer 來改善 Apache Traffic Server。

後來的後來,由於 uff 最主要的開發者離職,Apache Traffic Server 在 open source 社群中大量被改善效能,原本只能跑在 32bits 的環境,也改成對 64bits 相容。所以後來 Yahoo 又將 cdn 相關的 solution 改回來 Apache Traffic Server。


剛才講到 Apache Traffic Server 設計精良,內部對於 thread/event/network 都有各自的 processor,像是 carp 做 health check 的部分,就是丟給 event processor,然後會去呼叫 thread/network 相關的 processor 做更低階的處理,最後再透過 callback 之類的將最終狀態丟回原本的 caller。


讓我整個卡住的部分,其實就是在這邊,怎麼樣看,他都應該幫我開一個 tcp connection 出去,但是程式判斷的地方,他會先判斷 thread event type,如果不是他要的,就直接不處理,等到 event timeout 之後,就會去 callback 原本的 caller 來做後續的處理。可是我找不到任何的地方去決定 thread event type 呀!!!

因為我的 c++ skill 實在太差,在卡住三四天之後,覺得這樣下去不行,雖然手上有最終解決方案,就是 Apache Traffic Server cluster,但是終究是要 deprecated 的東西。所以我就開始找尋下一個替代方案,nginx 不行,因為 proxy mode 比較厲害的東西都被放在 nginx plus 裡面。那 varnish 呢?以前稍微試用過的經驗並不好。不過市面上可以用的 proxy 幾乎沒有了,每一套宣稱自己多厲害多厲害的 proxy,終究就只是很單純的 proxy,很多連自己對 client request/response, origin server request/response 都沒辦法額外處理。更不要講 performance 了。

在抱著試試看以及捧個人場的心情下,試用了一下 varnish cache,為什麼說捧個人場?因為 varnish 是 phk@freebsd.org 最近這十年來的力作,他幾乎都沒有再碰 kernel development,全心全力的做 varnish cache 的開發。

varnish cache 有下列幾個我覺得很棒的地方:
  1. bsd-2 clauses license,去他媽的 gpl。
  2. 沒有設定檔,一些參數都用 cli 方式傳進去,然後如果不會寫 vcl 也沒關係,backend server 相關資訊一樣可以用 cli 傳進去。
  3. vcl 很簡單,會寫簡單 perl 的人都會。
  4. vcl 不是直譯式處理,而是在 start-up 的時候,直接轉譯成 c code,馬上 compile 成 .so,varnishd load .so 起來處理,只要專心做好自己想要判斷的事情就好,memory leak/performance issue 等相關的事情完全不要理會。
  5. builtin vcl function 不夠用的話,可以自己寫 vmod 來擴充 function。
  6. log 什麼鬼的,varnish 全部都扔到 shared memory 去,另外有一隻 varnishlog 會從 shared memory 讀資料之後寫黨,所以什麼 log rotate 之類的事情,不用 kill -HUP varnishd,服務完全不會中斷。
  7. reload vcl 之類的也是可以 online 做,一樣服務不會中斷。
  8. 相關的 utility 做得非常好,varnishadm/varnishstat 之類的,幾乎都是商業等級的水準。
  9. 內建 health check,可以做到失敗幾次才會算真的失敗這類的情境。
  10. 支援各種 director,可以簡單應付各種場景。
    • fallback
    • hash
    • round robin
    • random
    • shard
不過 varnish 現在對我而言有一個瑕不掩瑜的缺點,雖然這個也可以用另外的程式做掉,但還是會覺得有點不舒服,那就是,他不支援 ssl,https 之類的要自己處理,這對於之後的 ios 可能會是個問題。

總之,varnish 算是簡單就達到我想要的功能,理論上會直接拿來使用。而 Apache Traffic Server 也不是完全沒有優點的,只是不會寫他的 plugin 的話,出廠預設的功能,其實是很難滿足需求。

2016年10月23日 星期日

Apache Traffic Server & Varnish Cache 之我見. (Part 1)

最近因為任務需要,需要自己弄一套 proxy/cache 的系統。

至於為什麼要自己弄?

  1. 當地國際頻寬貴,如果能在當地弄一份 static replica,可以省下很多錢。
  2. 但是在偏遠的地方自己弄 storage,光想營運成本就很高,尤其每樣都要做 HA 的時候,成本跟硬碟幾乎都是一路 * 2 * 3 上去。
  3. 既然不能搞 storage,那弄一份 cdn 總可以吧,基本上解決 20% 的 content,就省掉了 80% 的 cost。
  4. cdnetwork 之類的,幾乎都沒有在當地有 edge server。
  5. 所以即使用了 cdnetwork,還是要走國際頻寬出去,一樣貴。
原本想像中的架構如下:
  1. 最前面擋台 l4 load balancer,將流量 round robin 散到下面的 l7 load balancer 上。
  2. l7 load balancer 理論上會用 Apache Traffic Server 加上自己寫的 plugin,將前面進來的 request,透過 consistent hash 算過之後,平均導到後面的 storage 上面。
  3. consistent hash 只是個說法,重點是每台 l7 load balancer 自己要維護一份後面的 storage 的健康狀況表。
  4. storage 相對起來簡單,但是要能根據後面 Origin Server 的不同產生不同的 header 之類的,例如如果 Origin Server 是 S3,要能自動生出 s3 request header。
  5. 這樣做的好處在於,如果其中一台 l7 load balancer 壞掉,起碼有一台可以撐住。而後端的 storage,也會因為 l7 load balancer 已經用 consistent hash 算過,固定的 url 會送往固定某台,cache hit rate 會拉高,Origin Server 假設是 300T 好了,每台 storage 基本上可以只是部分就好,一旦任意一台 storage 壞掉,起碼可以先將 request 由隔壁來分擔,而不是全部養好的 cache 就全部掛光。





























剛才講到會用 Apache Traffic Server 來實做這些東西,為什麼呢?

  1. 畢竟我也是 ex-yahoo 呀。
  2. 畢竟我也摸了好一陣子的 yts & uff 呀。
  3. 畢竟我也是受到業界知名的嫩哥的薰陶。
Consistent Hash 就用 google 提出的 Jump Consistent Hash,而後端機器健康程度,要就是 plugin 自己開個 thread 定期去維護,不然就是透過 lmdb or mmap file 之類的,讓另外一支程式來幫你維護。

plugin 寫了一半,看到其實 Apache Traffic Server 有 cluster 的功能,看起來大方向其實跟我想做的雷同,只是方法不同。
ats cluster 的做法是,根本不分 l7 load balancer 還是 storage,全部都是 storage,只是一個 request 近來,會先查查自己肚子裡面有沒有 hit,沒有就發 udp multicast 出去問隔壁的有沒有人有 hit,有就直接抓來往 client 送。

諮詢嫩哥對於 ats cluster 的看法之後,他說 "cluster? 快要 deprecated 了呀" "現在你要用 carp 啦!"

carp 是什麼呢? 是 yahoo 針對這類的需求開發出來的一個 ats plugin,並且已經有送 pull request 給 ats 了,目標是在下一個版本的 ats 會包含這個 plugin。
想嚐鮮的可以先到 https://github.com/ericcarlschwartz/trafficserver/tree/TS-4723/plugins/experimental/carp 去查看。

既然 yahoo 都這麼有心,放出了方案給大家用,似乎不去試試看,好像還頗對不起 MM 的。

carp 光看設計,其實頗不錯的,health check 幫你做,也做 consistent hash,基本上我想要的他都做到了。很棒,立馬抓來 compile,load 進 ats 來試試看。

嗯嗯, 問題不大,最大的問題頂多是不會動而已!

對,他不會動,仔細查了一下相關的 code,寫法都是對的,但是他就是不會動!

好吧,一路追下去好了,TSContCreate,TSContSchedule,TSNetConnect 看起來每一樣都對呀!

不對,為什麼 TSNetConnect 裡面只要是 carp 要做 health check 的 connection,他就是直接不處理,然後最後等到 timeout?

喔,原來是 thread type 不對他就不處理呀!可是從頭到尾都沒有一個地方可以讓我自己決定要用哪種 thread 呀!

這個部分大概就卡了我三四天!!!