ATS插件开发基础
轉載自?https://blog.zymlinux.net/index.php/archives/540
ATS插件開發需要提前了解ATS的插件的一些設計思想,以及系統提供的一些不同方向。我們將會介紹ATS的基礎開發知識,以利于后續的插件開發課程講解。
ATS的SDK文檔,是了解ATS的核心設計、接口設計的很重要資料,甚至是老的PDF版本文檔,都是非常非常有用的資料。以至于我經常建議完全不了解ATS核心代碼的初學者也好好看看SDK文檔,這里講的很多基礎知識,有利于對核心的深入理解。ATS的API以及核心插件接口設計是一個很龐大的工程,其設計思想我們很難一下消化掉,這里點出一些知識點供大家參考。如有紕漏、謬誤之處,以SDK文檔、代碼注釋、代碼為準。
官方SDK文檔
歷史的SDK PDF文件
下一篇:手把手教你寫plugin
ATS開發環境
名詞解釋
-
HTTP Transaction
HTTP Transaction 是ATS特指http的處理流程,在ATS中,一個HTTP的請求的處理過程,叫做一個HTTP Transaction。ATS的很多API是以Transaction為核心的函數處理過程,也就賦予了這個過程以特殊的意義。在相關的API函數中,TSHttpTxn數據結構,以及以TSHttpTxn開頭的API函數都是圍繞這個處理流程來的。
-
HTTP SM
HTTP SM 是一般是指ATS的主流程狀態機,在ATS中,處理的流程是通過HTTP Transaction中的函數處理的,而狀態數據是存儲在HTTP SM中的。ATS核心主流程就是HTTP Transaction和HTTP SM的交互過程。
-
HTTP session
HTTP session是指http會話,一般指一個請求交互過程,特指如客戶端的一個請求,回源的一個請求,分別對應客戶端和服務器端HTTP session。對照HTTP Transaction,我們對應的ATS一個用戶請求引起的ATS HTTP Transaction,可以包含一個客戶端 HTTP Session,0個或1個甚至多個回源 HTTP Session。
-
remap
remap是ATS做URL rewrite的方式,也是ATS在配置文件設計方面的特殊部分。從功能上來講,ATS的remap更像一個精簡版本的Apache Httpd的rewrite模塊。remap之所以重要,是因為它定義了一個很方便的API入口,我們可以通過remap系統,編寫remap插件。
基礎知識:
-
Continuation
Continuation,從學術上應該是叫做Continuation的編程模型(方法),這個技術相當古老,后來微軟圍繞這個方案,改進出了coroutine的編程模型(方法),一定程度上來講Continuation是整個異步回調機制的多線程事件編程基礎。對應ATS中,Continuation是一個最最基礎的抽象結構,后續的所有高級結構,如Action Event VC等都封裝Continuation數據結構,我們先看Continuation結構的實際代碼:
class Continuation: private force_VFPT_to_top { public:ContinuationHandler handler;Ptr<proxymutex> mutex;LINK(Continuation, link);int handleEvent(int event = CONTINUATION_EVENT_NONE, void *data = 0) {return (this->*handler) (event, data);}Continuation(ProxyMutex * amutex = NULL); };Continuation主要包含:
- handler:當前的Continuation處理函數。
- mutex:Continuation的鎖。
- link:鏈接到其他Continuation的雙鏈表。
- handleEvent:接收event的代碼和數據,并交給當前的處理函數處理。
結構非常精煉,并不代表特殊含義。
Continuation在API中的結構叫TSCont,是插件開發中最常用到的抽象之一,是多數API要求的參數結構。在插件編程中的主要用到的如blacklit-0中的代碼:
TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(blacklist_plugin, NULL));這是一個hook函數,在
TS_HTTP_OS_DNS_HOOK階段,hook進去了blacklist_plugin(見下面代碼),而blacklist_plugin?函數事實上只是一個事件處理的handler而以,這里通過TSContCreate轉化為TSCont結構。通過這些API,插件開發者可以更關注業務流程實現,甚至都可以不用去理解ATS核心的復雜異步事件化機制,只需要照著例子來堆代碼就好啦。static int blacklist_plugin(TSCont contp, TSEvent event, void *edata) {TSHttpTxn txnp = (TSHttpTxn) edata;switch (event) {case TS_EVENT_HTTP_OS_DNS:handle_dns(txnp, contp);return 0;case TS_EVENT_HTTP_SEND_RESPONSE_HDR:handle_response(txnp);return 0;default:break;}return 0; } -
Action
Action是一個抽象出來的,由處理機處理的異步任務模型。這個任務是可以在異步處理環境中允許撤銷的。簡單的以為可以說是一個可以撤銷的函數機制?
這個結構的主要用處是用來構建統一的Event系統,用在底層的iocore/中的網絡以及磁盤IO等方面。當然,ATS的上層建筑更是依賴于它了。
class Action { public:Continuation * continuation;Ptr</proxymutex><proxymutex> mutex;volatile int cancelled;virtual void cancel(Continuation * c = NULL) {if (!cancelled)cancelled = true;}void cancel_action(Continuation * c = NULL) {if (!cancelled)cancelled = true;}Continuation *operator =(Continuation * acont){continuation = acont;if (acont)mutex = acont->mutex;elsemutex = 0;return acont;}Action():continuation(NULL), cancelled(false) {}virtual ~ Action() {} };關于Action,有幾個需要注意的地方:
- Action是可以再入的
- 撤銷必須是由任務的callback處理機來做
- 要撤銷必須先拿到鎖
- Action是由處理機創建的,在完成或撤銷的時候,也是由處理機負責的。狀態機不能在Action完成或撤銷后再訪問它
-
Event
Event是由Event處理機返回的一種Action。是可以用來調度出去從而異步處理的任務(Action)。event是不可再入的。由于它繼承自Action,因此也具有可以撤銷的機制,同時更可以在收到Event后處理或不處理而再調度出去,這個很亂啊:D
Event的調度分為4種:
- _imm:立即執行,這個模式講會直接讓Event進入待執行隊列
- _at:在未來某個具體時間,指定具體事件執行
- _in:在未來某段時間后,指定具體多久之后執行
-
_every:每隔多長事件,讓事件循環執行,類似cron等定時任務
class Event:public Action { public: void schedule_imm(int callback_event = EVENT_IMMEDIATE); void schedule_at(ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL); void schedule_in(ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL); void schedule_every(ink_hrtime aperiod, int callback_event = EVENT_INTERVAL); void free();
EThread *ethread;
unsigned int in_the_prot_queue:1; unsigned int in_the_priority_queue:1; unsigned int immediate:1; unsigned int globally_allocated:1; unsigned int in_heap:4; int callback_event;
ink_hrtime timeout_at; ink_hrtime period;
void *cookie;
Event(); Event *init(Continuation * c, ink_hrtime atimeout_at = 0, ink_hrtime aperiod = 0); private: void *operator new(size_t size); Event(const Event &); Event & operator =(const Event &);
public: LINK(Event, link); };
關于Event結構,有如下幾點需要注意:
- 狀態機只能在那個call-back線程中,發起調度,并且需要拿到continuation的鎖。
- 撤銷機制與Action類似,也需要在call-back狀態機拿到鎖的情況下做。
- 狀態機中,Event事件的代碼是需要全局統一的
-
VC
VConnection是ATS核心、插件都常用的一種面向stream的數據抽象結構。主要可以理解為一個數據讀寫管道,在某些場景下,有點類似FD的效果。VConnection繼承自continuation,也是會call-back到處理機處理的。這個基類是封裝上層通信管道的基礎。
VConnection提供關鍵的幾個接口:
- do_io_read
- do_io_write
- do_io_close
- do_io_shutdown
- reenable 用來通知另一端可以實施下一步動作
-
set_continuation
class VConnection:public Continuation { public:
virtual ~ VConnection();
virtual VIO *do_io_read(Continuation *c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) = 0; virtual VIO *do_io_write(Continuation *c = NULL, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) = 0; virtual void do_io_close(int lerrno = -1) = 0; virtual void do_io_shutdown(ShutdownHowTo_t howto) = 0;
VConnection(ProxyMutex *aMutex); virtual void set_continuation(VIO *vio, Continuation *cont); virtual void reenable(VIO *vio); virtual void reenable_re(VIO *vio);
virtual bool get_data(int id, void *data) { (void) id; (void) data; return false; } virtual bool set_data(int id, void *data) { (void) id; (void) data; return false; }
public: int lerrno; };
VConnection定義了一個可以串聯的虛擬管道,可以讓ATS在網絡、狀態機、磁盤間形成流式數據通信,是上層通信機制的很關鍵一環。
語言與接口
-
C API
ATS默認的API是C API,即ts.h,這是C的API,據某人說用C++程序封裝出C API很強大,不明覺歷。
ATS同時還有一些個非穩定的API,定義在:experimental.h
還有2個API文件,默認并沒有提供給大家
- InkAPIHughes.h 為Hughes設計的Prefetch API,用到Prefetch功能的可以看看。
- InkAPIPrivateIOCore.h 很底層的API,如鎖、Buffer、網絡包等,應該沒有需要用到的必要。
-
C++ API
LinkIn 公司為ATS添加了一套C++的API,需要在編譯的時候加?
--with-cpp11api?選項configure才行。C++ API包含:
- ts-cpp11.h
- ts-cpp11-headers.h
這個API可能不夠完備
ATS插件環境
-
ATS 插件模式
- global:這種模式的插件,是會對全局有效,可以有效攔截整個流程,包括客戶端建連過程。
- remap:在用戶請求經過remap完成后的階段hook進去,是一個添加網站應用邏輯的地方。
-
ATS 插件模板
- global
- TBD 我希望能夠用
tsxs這個工具能夠生成一些模板代碼,正在整理中
- TBD 我希望能夠用
- remap
- TBD
- global
ATS核心流程
- 流程
- hook點
關于狀態機
-
主HttpSM
HttpSM是指ATS的核心http流程狀態機,即proxy/http/HttpSM.cc(.h)中定義的狀態機,這是整個proxy業務的大狀態機,所有的其他流程都是依附于(或關聯于)這個狀態機上的。如回源、讀寫cache等。當然這個文件也是目前ATS中最大的2個文件之一,以近萬行的代碼挑戰你的能力。
HttpSM相對插件開發者來說,幾乎是不可見的,因為所有的插件都是hook到整個http流程中間來的。只有想看核心代碼的同學才有意義。
-
子狀態機
所謂子狀態機,其實在ATS的事件系統里,到處都是,只要是做一個稍微復雜點的異步處理必然要引入一個狀態機(processor)來做,相對來說這些都比較微型化。
ATS的主HttpSM狀態機并不是完全不可控制的,ATS允許你很大程度的自己定制自己的狀態機,甚至繞過絕大多數HttpSM流程,這里可以參考的代碼有:
- Prefetch:proxy/Prefetch.cc(.h),這是一個做到核心中的transform插件,在用戶訪問html的時候,解析html并提取所有頁面元素,主動發起回源以預取,提高用戶感受。這里的核心是一個后臺回源狀態機,典型的設計可以參考。
- example/protocol,這是一個完全脫離HttpSM的協議代碼例子,這里定義了一個protocol插件,直接accept并且自己建立了自己的SM狀態機,走自己的獨立流程(TxnSM.c)。
ATS代碼樹
-
iocore
IOcore系統是定義最核心的ATS基礎模塊,定義了底層的所有關鍵框架,這些模塊和框架與業務系統相對獨立,其中包括:
- eventsystem 事件系統,定義了事件系統的調度機制、buffer管理系統等等
- net 網絡層,定義了網絡處理的基礎框架
- aio 異步IO的實現,實現了類似于libc的AIO線程方案
- cache 緩存與文件系統,管理磁盤存儲、內存cache等
- cluster 集群通信系統,解決集群數據交互協議RPC
- dns DNS解析代碼,我們需要在異步環境下做DNS的解析客戶端
- hostdb DNS緩存系統,解決了DNS的中間cache
IOcore系統,代碼邏輯相對隔離的還是不錯的,因此各個模塊是能夠比較獨立的理解和學習的。
-
proxy
Proxy模塊可以說是ATS的業務邏輯,也是traffic_server的主代碼所在地。
Proxy下有幾個比較關鍵的模塊:
- logging:所謂的access日志模塊
- api:我們所說的API都是定義在這里的。(C++API放在lib目錄下)
- config:ATS的配置文件源文件目錄
- http:這是關鍵的狀態機目錄
其他各種功能,都放在proxy/目錄下,這里也是功能最多、最亂的一灘子啦。
-
cop
cop是用來存放traffic_cop代碼的,相對來說是最簡單的代碼啦。
-
mgmt
這里存放的是traffic_manager代碼。其中仍有許多需要清理的老代碼殘渣。
-
lib
這里存放的是ATS的基礎庫,繼承自原Inktomi++的仿C++標準庫,ATS對外部庫依賴比較少皆因這個庫成型比較早,并且覆蓋面比較全面。某人說這個就是C++標準庫啊。話說當年(95-99年)ATS開發的時候,C++標準還在娘胎中吧?
lib下有幾個關鍵模塊:
- ts:即所說的ATS C++標準庫
- records:這個目錄是stats|records系統的關鍵
-
example
存放SDK介紹的,以及未介紹的所有插件參考代碼。可以放心的說,ATS能夠做的場景,在這個目錄下都可以找到比較接近的例子。從這里的代碼開始業務編程是很好的選擇。
-
tools
存放性能測試工具如http_load jtest工具以及狀態跟蹤工具tstop等
-
plugins
存放所有公開到主代碼的插件系統代碼:
- esi
- cacheurl
- regex_remap
- 其他experimental插件
-
doc
存放Admin手冊、man手冊等
-
rc
init腳本等
總結
- 上一篇: Tafficserver旁路接入方案综述
- 下一篇: 为方便ATS管理建立的一些命令别名