ATS插件开发基础
轉(zhuǎn)載自?https://blog.zymlinux.net/index.php/archives/540
ATS插件開發(fā)需要提前了解ATS的插件的一些設(shè)計(jì)思想,以及系統(tǒng)提供的一些不同方向。我們將會(huì)介紹ATS的基礎(chǔ)開發(fā)知識(shí),以利于后續(xù)的插件開發(fā)課程講解。
ATS的SDK文檔,是了解ATS的核心設(shè)計(jì)、接口設(shè)計(jì)的很重要資料,甚至是老的PDF版本文檔,都是非常非常有用的資料。以至于我經(jīng)常建議完全不了解ATS核心代碼的初學(xué)者也好好看看SDK文檔,這里講的很多基礎(chǔ)知識(shí),有利于對(duì)核心的深入理解。ATS的API以及核心插件接口設(shè)計(jì)是一個(gè)很龐大的工程,其設(shè)計(jì)思想我們很難一下消化掉,這里點(diǎn)出一些知識(shí)點(diǎn)供大家參考。如有紕漏、謬誤之處,以SDK文檔、代碼注釋、代碼為準(zhǔn)。
官方SDK文檔
歷史的SDK PDF文件
下一篇:手把手教你寫plugin
ATS開發(fā)環(huán)境
名詞解釋
-
HTTP Transaction
HTTP Transaction 是ATS特指http的處理流程,在ATS中,一個(gè)HTTP的請(qǐng)求的處理過程,叫做一個(gè)HTTP Transaction。ATS的很多API是以Transaction為核心的函數(shù)處理過程,也就賦予了這個(gè)過程以特殊的意義。在相關(guān)的API函數(shù)中,TSHttpTxn數(shù)據(jù)結(jié)構(gòu),以及以TSHttpTxn開頭的API函數(shù)都是圍繞這個(gè)處理流程來的。
-
HTTP SM
HTTP SM 是一般是指ATS的主流程狀態(tài)機(jī),在ATS中,處理的流程是通過HTTP Transaction中的函數(shù)處理的,而狀態(tài)數(shù)據(jù)是存儲(chǔ)在HTTP SM中的。ATS核心主流程就是HTTP Transaction和HTTP SM的交互過程。
-
HTTP session
HTTP session是指http會(huì)話,一般指一個(gè)請(qǐng)求交互過程,特指如客戶端的一個(gè)請(qǐng)求,回源的一個(gè)請(qǐng)求,分別對(duì)應(yīng)客戶端和服務(wù)器端HTTP session。對(duì)照HTTP Transaction,我們對(duì)應(yīng)的ATS一個(gè)用戶請(qǐng)求引起的ATS HTTP Transaction,可以包含一個(gè)客戶端 HTTP Session,0個(gè)或1個(gè)甚至多個(gè)回源 HTTP Session。
-
remap
remap是ATS做URL rewrite的方式,也是ATS在配置文件設(shè)計(jì)方面的特殊部分。從功能上來講,ATS的remap更像一個(gè)精簡(jiǎn)版本的Apache Httpd的rewrite模塊。remap之所以重要,是因?yàn)樗x了一個(gè)很方便的API入口,我們可以通過remap系統(tǒng),編寫remap插件。
基礎(chǔ)知識(shí):
-
Continuation
Continuation,從學(xué)術(shù)上應(yīng)該是叫做Continuation的編程模型(方法),這個(gè)技術(shù)相當(dāng)古老,后來微軟圍繞這個(gè)方案,改進(jìn)出了coroutine的編程模型(方法),一定程度上來講Continuation是整個(gè)異步回調(diào)機(jī)制的多線程事件編程基礎(chǔ)。對(duì)應(yīng)ATS中,Continuation是一個(gè)最最基礎(chǔ)的抽象結(jié)構(gòu),后續(xù)的所有高級(jí)結(jié)構(gòu),如Action Event VC等都封裝Continuation數(shù)據(jù)結(jié)構(gòu),我們先看Continuation結(jié)構(gòu)的實(shí)際代碼:
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:當(dāng)前的Continuation處理函數(shù)。
- mutex:Continuation的鎖。
- link:鏈接到其他Continuation的雙鏈表。
- handleEvent:接收event的代碼和數(shù)據(jù),并交給當(dāng)前的處理函數(shù)處理。
結(jié)構(gòu)非常精煉,并不代表特殊含義。
Continuation在API中的結(jié)構(gòu)叫TSCont,是插件開發(fā)中最常用到的抽象之一,是多數(shù)API要求的參數(shù)結(jié)構(gòu)。在插件編程中的主要用到的如blacklit-0中的代碼:
TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(blacklist_plugin, NULL));這是一個(gè)hook函數(shù),在
TS_HTTP_OS_DNS_HOOK階段,hook進(jìn)去了blacklist_plugin(見下面代碼),而blacklist_plugin?函數(shù)事實(shí)上只是一個(gè)事件處理的handler而以,這里通過TSContCreate轉(zhuǎn)化為TSCont結(jié)構(gòu)。通過這些API,插件開發(fā)者可以更關(guān)注業(yè)務(wù)流程實(shí)現(xiàn),甚至都可以不用去理解ATS核心的復(fù)雜異步事件化機(jī)制,只需要照著例子來堆代碼就好啦。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是一個(gè)抽象出來的,由處理機(jī)處理的異步任務(wù)模型。這個(gè)任務(wù)是可以在異步處理環(huán)境中允許撤銷的。簡(jiǎn)單的以為可以說是一個(gè)可以撤銷的函數(shù)機(jī)制?
這個(gè)結(jié)構(gòu)的主要用處是用來構(gòu)建統(tǒng)一的Event系統(tǒng),用在底層的iocore/中的網(wǎng)絡(luò)以及磁盤IO等方面。當(dāng)然,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() {} };關(guān)于Action,有幾個(gè)需要注意的地方:
- Action是可以再入的
- 撤銷必須是由任務(wù)的callback處理機(jī)來做
- 要撤銷必須先拿到鎖
- Action是由處理機(jī)創(chuàng)建的,在完成或撤銷的時(shí)候,也是由處理機(jī)負(fù)責(zé)的。狀態(tài)機(jī)不能在Action完成或撤銷后再訪問它
-
Event
Event是由Event處理機(jī)返回的一種Action。是可以用來調(diào)度出去從而異步處理的任務(wù)(Action)。event是不可再入的。由于它繼承自Action,因此也具有可以撤銷的機(jī)制,同時(shí)更可以在收到Event后處理或不處理而再調(diào)度出去,這個(gè)很亂啊:D
Event的調(diào)度分為4種:
- _imm:立即執(zhí)行,這個(gè)模式講會(huì)直接讓Event進(jìn)入待執(zhí)行隊(duì)列
- _at:在未來某個(gè)具體時(shí)間,指定具體事件執(zhí)行
- _in:在未來某段時(shí)間后,指定具體多久之后執(zhí)行
-
_every:每隔多長(zhǎng)事件,讓事件循環(huán)執(zhí)行,類似cron等定時(shí)任務(wù)
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); };
關(guān)于Event結(jié)構(gòu),有如下幾點(diǎn)需要注意:
- 狀態(tài)機(jī)只能在那個(gè)call-back線程中,發(fā)起調(diào)度,并且需要拿到continuation的鎖。
- 撤銷機(jī)制與Action類似,也需要在call-back狀態(tài)機(jī)拿到鎖的情況下做。
- 狀態(tài)機(jī)中,Event事件的代碼是需要全局統(tǒng)一的
-
VC
VConnection是ATS核心、插件都常用的一種面向stream的數(shù)據(jù)抽象結(jié)構(gòu)。主要可以理解為一個(gè)數(shù)據(jù)讀寫管道,在某些場(chǎng)景下,有點(diǎn)類似FD的效果。VConnection繼承自continuation,也是會(huì)call-back到處理機(jī)處理的。這個(gè)基類是封裝上層通信管道的基礎(chǔ)。
VConnection提供關(guān)鍵的幾個(gè)接口:
- do_io_read
- do_io_write
- do_io_close
- do_io_shutdown
- reenable 用來通知另一端可以實(shí)施下一步動(dòng)作
-
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定義了一個(gè)可以串聯(lián)的虛擬管道,可以讓ATS在網(wǎng)絡(luò)、狀態(tài)機(jī)、磁盤間形成流式數(shù)據(jù)通信,是上層通信機(jī)制的很關(guān)鍵一環(huán)。
語言與接口
-
C API
ATS默認(rèn)的API是C API,即ts.h,這是C的API,據(jù)某人說用C++程序封裝出C API很強(qiáng)大,不明覺歷。
ATS同時(shí)還有一些個(gè)非穩(wěn)定的API,定義在:experimental.h
還有2個(gè)API文件,默認(rèn)并沒有提供給大家
- InkAPIHughes.h 為Hughes設(shè)計(jì)的Prefetch API,用到Prefetch功能的可以看看。
- InkAPIPrivateIOCore.h 很底層的API,如鎖、Buffer、網(wǎng)絡(luò)包等,應(yīng)該沒有需要用到的必要。
-
C++ API
LinkIn 公司為ATS添加了一套C++的API,需要在編譯的時(shí)候加?
--with-cpp11api?選項(xiàng)configure才行。C++ API包含:
- ts-cpp11.h
- ts-cpp11-headers.h
這個(gè)API可能不夠完備
ATS插件環(huán)境
-
ATS 插件模式
- global:這種模式的插件,是會(huì)對(duì)全局有效,可以有效攔截整個(gè)流程,包括客戶端建連過程。
- remap:在用戶請(qǐng)求經(jīng)過remap完成后的階段hook進(jìn)去,是一個(gè)添加網(wǎng)站應(yīng)用邏輯的地方。
-
ATS 插件模板
- global
- TBD 我希望能夠用
tsxs這個(gè)工具能夠生成一些模板代碼,正在整理中
- TBD 我希望能夠用
- remap
- TBD
- global
ATS核心流程
- 流程
- hook點(diǎn)
關(guān)于狀態(tài)機(jī)
-
主HttpSM
HttpSM是指ATS的核心http流程狀態(tài)機(jī),即proxy/http/HttpSM.cc(.h)中定義的狀態(tài)機(jī),這是整個(gè)proxy業(yè)務(wù)的大狀態(tài)機(jī),所有的其他流程都是依附于(或關(guān)聯(lián)于)這個(gè)狀態(tài)機(jī)上的。如回源、讀寫cache等。當(dāng)然這個(gè)文件也是目前ATS中最大的2個(gè)文件之一,以近萬行的代碼挑戰(zhàn)你的能力。
HttpSM相對(duì)插件開發(fā)者來說,幾乎是不可見的,因?yàn)樗械牟寮际莌ook到整個(gè)http流程中間來的。只有想看核心代碼的同學(xué)才有意義。
-
子狀態(tài)機(jī)
所謂子狀態(tài)機(jī),其實(shí)在ATS的事件系統(tǒng)里,到處都是,只要是做一個(gè)稍微復(fù)雜點(diǎn)的異步處理必然要引入一個(gè)狀態(tài)機(jī)(processor)來做,相對(duì)來說這些都比較微型化。
ATS的主HttpSM狀態(tài)機(jī)并不是完全不可控制的,ATS允許你很大程度的自己定制自己的狀態(tài)機(jī),甚至繞過絕大多數(shù)HttpSM流程,這里可以參考的代碼有:
- Prefetch:proxy/Prefetch.cc(.h),這是一個(gè)做到核心中的transform插件,在用戶訪問html的時(shí)候,解析html并提取所有頁面元素,主動(dòng)發(fā)起回源以預(yù)取,提高用戶感受。這里的核心是一個(gè)后臺(tái)回源狀態(tài)機(jī),典型的設(shè)計(jì)可以參考。
- example/protocol,這是一個(gè)完全脫離HttpSM的協(xié)議代碼例子,這里定義了一個(gè)protocol插件,直接accept并且自己建立了自己的SM狀態(tài)機(jī),走自己的獨(dú)立流程(TxnSM.c)。
ATS代碼樹
-
iocore
IOcore系統(tǒng)是定義最核心的ATS基礎(chǔ)模塊,定義了底層的所有關(guān)鍵框架,這些模塊和框架與業(yè)務(wù)系統(tǒng)相對(duì)獨(dú)立,其中包括:
- eventsystem 事件系統(tǒng),定義了事件系統(tǒng)的調(diào)度機(jī)制、buffer管理系統(tǒng)等等
- net 網(wǎng)絡(luò)層,定義了網(wǎng)絡(luò)處理的基礎(chǔ)框架
- aio 異步IO的實(shí)現(xiàn),實(shí)現(xiàn)了類似于libc的AIO線程方案
- cache 緩存與文件系統(tǒng),管理磁盤存儲(chǔ)、內(nèi)存cache等
- cluster 集群通信系統(tǒng),解決集群數(shù)據(jù)交互協(xié)議RPC
- dns DNS解析代碼,我們需要在異步環(huán)境下做DNS的解析客戶端
- hostdb DNS緩存系統(tǒng),解決了DNS的中間cache
IOcore系統(tǒng),代碼邏輯相對(duì)隔離的還是不錯(cuò)的,因此各個(gè)模塊是能夠比較獨(dú)立的理解和學(xué)習(xí)的。
-
proxy
Proxy模塊可以說是ATS的業(yè)務(wù)邏輯,也是traffic_server的主代碼所在地。
Proxy下有幾個(gè)比較關(guān)鍵的模塊:
- logging:所謂的access日志模塊
- api:我們所說的API都是定義在這里的。(C++API放在lib目錄下)
- config:ATS的配置文件源文件目錄
- http:這是關(guān)鍵的狀態(tài)機(jī)目錄
其他各種功能,都放在proxy/目錄下,這里也是功能最多、最亂的一灘子啦。
-
cop
cop是用來存放traffic_cop代碼的,相對(duì)來說是最簡(jiǎn)單的代碼啦。
-
mgmt
這里存放的是traffic_manager代碼。其中仍有許多需要清理的老代碼殘?jiān)?/p>
-
lib
這里存放的是ATS的基礎(chǔ)庫,繼承自原Inktomi++的仿C++標(biāo)準(zhǔn)庫,ATS對(duì)外部庫依賴比較少皆因這個(gè)庫成型比較早,并且覆蓋面比較全面。某人說這個(gè)就是C++標(biāo)準(zhǔn)庫啊。話說當(dāng)年(95-99年)ATS開發(fā)的時(shí)候,C++標(biāo)準(zhǔn)還在娘胎中吧?
lib下有幾個(gè)關(guān)鍵模塊:
- ts:即所說的ATS C++標(biāo)準(zhǔn)庫
- records:這個(gè)目錄是stats|records系統(tǒng)的關(guān)鍵
-
example
存放SDK介紹的,以及未介紹的所有插件參考代碼。可以放心的說,ATS能夠做的場(chǎng)景,在這個(gè)目錄下都可以找到比較接近的例子。從這里的代碼開始業(yè)務(wù)編程是很好的選擇。
-
tools
存放性能測(cè)試工具如http_load jtest工具以及狀態(tài)跟蹤工具tstop等
-
plugins
存放所有公開到主代碼的插件系統(tǒng)代碼:
- esi
- cacheurl
- regex_remap
- 其他experimental插件
-
doc
存放Admin手冊(cè)、man手冊(cè)等
-
rc
init腳本等
總結(jié)
- 上一篇: Tafficserver旁路接入方案综述
- 下一篇: 为方便ATS管理建立的一些命令别名