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 呀!

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

2016年3月23日 星期三

[Elixir] 安裝 erlang + elixir + phoenix framework

elixir 是架構在 erlang vm 上的語言,所以在開發程式之前,第一件事就是把 erlang 裝起。



  • Linux
    • 由於個人使用習慣,平常我個人都用 FreeBSD,linux 我大概只用 rhel/centos。
    • rpm 可以在 Erlang Solutions 下載,不過這個版本會順便將 wxGtk 也裝起來,個人並不喜歡。
    • 可以使用 rabbitmq 做好的 zero dependencies rpm
  • FreeBSD
    • 透過 ports,直接到 lang/erlang 下面 make install 就好了。
裝好了 erlang,下一步就是把 elixir 也裝好。
  • Linux
    • 我不確定有哪一個 distribution已經內建 elixir,但是同樣的  Erlang Solutions 有 package,但是只有給 debian/ubuntu 的而已。
    • 所以直接到 elixir 的 github 下載,解開之後打個 make install 就裝好了。
  • FreeBSD
    • 一樣很簡單,到 lang/elixir 下面 make install 就裝好了。
裝好 elixir 之後,基本上會有兩個東西會不停地在開發過程被用到:
  • mix - project management tool,任何你在開發過程會用到的工具或者流程,都會透過 mix 這一個 command 來執行,另外也可以自行編寫 mix task 擴充功能。
  • iex - interactive elixir shell,就是一個 elixir shell,一些簡單的想法可以直接在 iex 裡面實現及驗證。
再來就是安裝 phoenix framework,這東西有點像是蛋跟雞一樣,你要有 phoenix 的 mix task,才能夠建立一個 phoenix project,但是你也要先有相關的 package 安裝好了,才能有 phoenix mix task 能夠被使用。不過沒問題,elixir & phoenix team 都幫你想好了,透過 mix archive.install 就可以把 phoenix 裝好。

 mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez  

裝好 phoenix 之後,打 mix -h 就可以發現多了一個 mix phoenix.new 的 task 可以用。
也可以打一下 'mix phoenix.new -h' 來看看相關參數。

2016年3月10日 星期四

[Elxir] 為什麼要用 elixir 呢?

開始的開始,其實我是先知道 erlang 這個語言的。

大約在 2007/2008 左右,那時候應該還是在 erlang 13.x 的版本,我忘記我從哪邊知道這個語言,一直想好好學好它,也買了書來看。

但是大概是 perl/php 這類語言的餘毒,讓我在學習 functional language 的路上沒能好好走完。
雖然一直都沒學好,不過我都還是持續在關心著 erlang,尤其這中間很多公司,都用了 erlang 做一堆神經病等級的產品,例如 whatsapp,例如 cowboy 等等。

而 elixir 這個架構在 erlang vm 上的語言,我大概是兩三年前在 erlang 的社群略有耳聞,但是由於之前對於 erlang 一直學不好的心理因素,就一直忽視他。

那到底是什麼樣的機緣,又讓我再度擁抱 erlang 甚至開始學習 elixir 呢?應該是因為工作需要吧!因為一些先天上的限制,軟體的 dependencies 其實是困擾的所有的開發人員,尤其是開發電信機房裡面的服務。

一開始我們選擇的 golang,寫起來簡單,相關的 unit test 都具備了,但是又似乎少了點什麼,如果程式因為任意原因死掉了,你必須自己監控,必須自己想辦法。即使 golang 有了 static link 這個降低 dependencies 的好處,但那還是不夠呀。

所以大約在去年七月,經過一些評估之後,我重回了 erlang/elixir 的懷抱:

  • ecosystem 完善
    • 有 hex.pm 這一個 package management site,任何人寫的東西都可經由這個網站發布,也可以輕易的跟 project 結合。
    • elixir 內建了 mix 這一個 project management tool,任何開發期需要的東西,都可以透過這個工具去呼叫,也可以自己寫 mix task 來把複雜的事情變簡單。
  • otp
    • Open Telecomm Platform
    • erlang 內建 otp,因為 erlang 就是為了交換機而被發明的語言,所以他很多特性,都是為了電信業而產生。
    • 而 otp 本身就有很多先進的設計,就是為了確保服務儘可能地沒有 downtime,例如 supervisor 可以檢控 process,當他掛掉會自動重新叫起來。例如 code hot swap 可以讓 daemon 持續服務,但是瞬間將版本升級。
  • async
    • 在 erlang 裡面,每一個 app 都是獨立的一個 erlang process,彼此用 message passing 溝通,所以要寄信,直接將相關資料扔給寄信的 process 即可,前端的 web 可以繼續服務。
  • no side effect
    • 也由於資料並沒有 lock 這類的問題,所以儘可能地降低 side effect。
  • 接近人類思考模式
    • erlang 說真的我還是沒認真寫過,但是 elixir 幾乎已經接近人類思考模式了,人並不會做一件事情,只有一個 function 然後裡面一堆 if/else,而是在最開始,就已經把很多事情直接分開。這樣的好處是,每個 function 就只做自己的事情。
  • phoenix framework
    • 如果只有 elixir + mix 這樣的工具,其實還沒辦法好好做事,畢竟什麼東西都還是要有個漂亮的介面。
    • phoenix framework 是用 elixir 寫的 web framework,再加上 ecto 之後,資料庫什麼鬼的都抽象化了。
    • 簡單的說,elixir 就像是 ruby,phoenix 就像是 ror,而依賴著 erlang 天生的高效能,可以快速地生出很棒的服務出來。
  • exrm + rpm
    • exrm 是一個 release tool,經過 exrm 的 task 處理過後,可以生出一個 .tar.gz 檔。
    • 將這個檔案直接 copy 到機器上,解開就可以直接跑起服務。
    • 像是 erlang vm 什麼的,都會在這個 .tar.gz 裡面。根本不需要預先安裝甚麼軟體。
    • 但是只有 exrm 對很多人來說可能還是不夠,所以有人又替 exrm 衍生出 exrm_rpm。
    • exrm_rpm 在 exrm 的基礎上,可以在 task 的最後,把 .tar.gz 轉成一個 .rpm。
    • 這個 rpm 裡面連 init.d 的 script 都有了,直接 yum install xxx.rpm,重新開機就所有服務一次到位。
評估完,就開始將原本用 php 寫的 web tool 改用 elixir 寫,整個工作從去年八月開始,中間加入了一些 linter,code analyst tools,並在今年二月左右,將整個 unit test/integration test 都做完,最後的 code coverage 約 85%。

本篇為起手式,之後會開始從怎樣弄一個 elixir project 講起,到我中間有用過的工具,然後最後以包出一個 rpm 為結束。

(不保證什麼時候會做好。)