Trafficserver的主要功能是緩存,固然你也能夠用它來作純粹的反向代理(像一般用nginx那樣)。一般切入一個龐大的系統的最好方式是看如何使用,使用traffic server的主要入口有兩個:配置文件和插件。全部使用者都須要配置文件,高級使用者則須要插件。css
traffic支持大規模的集羣處理,不一樣於nginx的單點(須要ospf均衡鏈路來作冗餘),全部的配置文件能夠作到改動一個通知所有。程序根據功能劃分爲不一樣的幾個子程序,有服務運行時使用的程序,也有管理使用的。詳細見下文。html
[root@controller trafficserver]# tree -L 3 bin/ etc/ var/ bin/ ├── traffic_cop ├── traffic_crashlog ├── traffic_ctl ├── traffic_layout ├── traffic_line ├── traffic_logcat ├── traffic_logstats ├── traffic_manager ├── traffic_sac ├── trafficserver ├── traffic_server ├── traffic_top ├── traffic_via ├── tspush ├── tstop -> traffic_top └── tsxs etc/ └── trafficserver ├── body_factory │ └── default ├── cache.config ├── cache.config_1 ├── cluster.config ├── cluster.config_1 ├── congestion.config ├── congestion.config_1 ├── hosting.config ├── hosting.config_1 ├── icp.config ├── icp.config_1 ├── ip_allow.config ├── ip_allow.config_1 ├── log_hosts.config ├── log_hosts.config_1 ├── logs_xml.config ├── logs_xml.config_1 ├── parent.config ├── parent.config_1 ├── plugin.config ├── plugin.config_1 ├── prefetch.config ├── prefetch.config_1 ├── proxy.pac ├── proxy.pac_1 ├── records.config ├── records.config_1 ├── remap.config ├── remap.config_1 ├── remap.config_2 ├── snapshots ├── socks.config ├── socks.config_1 ├── splitdns.config ├── splitdns.config_1 ├── ssl_multicert.config ├── ssl_multicert.config_1 ├── stats.config.xml ├── stats.config.xml_1 ├── storage.config ├── storage.config_1 ├── storage.config_2 ├── trafficserver-release ├── update.config ├── update.config_1 ├── vaddrs.config ├── vaddrs.config_1 ├── volume.config └── volume.config_1 var/ ├── log │ └── trafficserver │ ├── access.log_controller.19691231.19h00m00s-20171201.00h00m04s.old │ ├── access.log_controller.20171201.00h35m04s-20171201.02h00m02s.old │ ├── diags.log │ ├── error.log │ ├── manager.log │ ├── squid.blog │ ├── squid.blog_controller.19691231.19h00m00s-20171201.00h00m04s.old │ ├── traffic.out │ ├── traffic_server.stderr │ └── traffic_server.stdout └── trafficserver ├── cache.db ├── cop.lock ├── eventapi.sock ├── host.db ├── hostdb.config ├── manager.lock ├── mgmtapi.sock ├── processerver.sock ├── records.snap ├── server.lock └── stats.snap
l 緩存Cache.configlinux
n 上游拉取數據擁塞控制:congestion.confignginx
n 緩存分割與上游分配:hosting.configgolang
n 劃分不一樣種類的緩存類型(與hosting.config配合能夠實現不一樣種的數據緩存安排)算法
n 定義上游的peer:Icp.configapache
n 定義可使用cache的白名單:ip_allow.config編程
n 緩存能夠定義多級,定義級別的配置:parent.config後端
n 緩存持久化:storage.configapi
l Log配置
n 將不一樣上游的log放到不一樣的log文件中:log_hosts.config
n 定義不一樣的log格式:logs_xml.config
l 插件管理plugins.config
l 主程序可調整參數:records.config
l 代理:
n 請求和響應的url修改配置:remap.config
l 域名解析:splitdns.config
l 安全:配置多個ssl證書:ssl_multicert.config
標準的面向過程作插件的過程。一個HTTP有個處理流程,包括request頭部處理(你能夠改url),dns查詢(你能夠決定去哪一個後臺獲取數據)、從後臺或緩存拉取數據、返回內容等。只要是http請求,這個流程就是固定的。所以插件系統就是在這些流程上註冊回調函數。這裏的回調函數還不是直接調用,還會傳遞一個event事件參數,用於表示在當前的鉤子上發生的事情,使plugin能夠更好的處理。
除了被調用,trafficserver還要提供調用方法。這裏提供的調用方式可不是通常意義上的函數調用,而是相似遠程過程調用。插件經過將本身要被執行的代碼(action)發送給server(就連發送都是要指明ip地址和端口的),而後經過查詢server返回的接口來得到action執行的狀態。這裏的action就是traffic server裏面的協程概念,整個過程相似golang的go func(){}()關鍵字操做。
除了這種遠程調用,不少函數插件也是能夠直接調用的。
協程:
Trafficserver的超高併發天然須要協程的概念(ng也是)。Traffic server本身實現的協程叫作continuation,結構體用TSCont表示。
一個TSCont表明一個異步執行的代碼塊,這個代碼塊擁有本身的執行狀態,而且能夠被
協程是用戶空間管理的線程,也就是說調度算法是在用戶空間的程序中實現的。能夠保存程序執行的狀態,能夠在某時刻拉出來執行。多個協程在一個操做系統的線程上執行,或者是M個協程在N個線程上執行。如此帶來的好處是能夠任性的阻塞,沒必要擔憂資源的浪費問題。因此協程本質上也是一種應對阻塞調用的方式。其餘的重要思想還有異步。貌似操做系統更傾向於異步,而不是傾向於協程。
Trafficserver底層大量基於異步,但向上提供的併發卻大量基於協程的概念。
插件類型:
內容變換
內容變換是修改request的內容或者response的內容。因爲內容是變長的,因此traffic server定義了vconnection(結構體TSVConn)和vio。Vconnection表明從一個buffer到另外一個buffer的鏈接,通過這個鏈接的數據能夠根據鏈接指定的變化方法變化。這也就是內容變換的本質。本質上TSVConn是一個continuation,因此也具有協continuation具有的數據通知能力。
而VIO是VConnection兩端。一個input一個output,因爲能夠多個vconnection串行,因此一個vconnection的output vio就能夠另外一個vconnection的input。Vconnection的本質是變換,VIO的本質是內存buffer。
其餘協議插件
這個就比較底層了。通常的插件都是服務於http協議的,你也能夠直接跳過http協議支持別的協議,或者是支持http之上的其餘協議。課件traffic server對其網絡基礎結構的信心。
插件提升:
每一個插件都必須包含voidTSPluginInit(int argc, const char *argv[])函數,熟悉C的很容易理解,固定的名字和參數對應着固定的符號表符號,當插件被加載的時候,主程序能夠直接按照這個符號表去執行就行了,這就是入口。
1. 向主程序註冊插件:TSPluginRegister。能夠不註冊,主要是爲了兼容性
2. 向某個全局鉤子位置添加鉤子回調:TSHttpHookAdd
a) 註冊的鉤子能夠是全局的也多是trasaction、session相關的。若是是transaction相關的,經過TSHttpTxn txnp = (TSHttpTxn)edata;得到transaction的指針。使用TSHttpTxnHookAdd函數添加transactionhook。
b) 若是是session相關的,使用TSHttpSsnHookAdd進行註冊。Plugin中得到session的方法變爲TSHttpSsn ssion = (TSHttpSsn)edata;
插件容許發起網絡鏈接,使用TSNetConnect()發起只鏈接traffic server的http鏈接,TSHttpConnect()發起向任意地址的http鏈接。
使用ats無非就是反向代理和緩存兩種,其中緩存是ats最重要的功能。要想理解ats的cache架構,理解幾個關鍵字和概念就行了。
還有就是ats的cache能夠組成集羣,有兩種方式:一種是配置共享的,一種是統一緩存的。配置共享的只是保證各個節點的配置是同樣的,各個節點的cache仍是各自緩存(重複是確定有的),而統一緩存則是互相協做的,在多個節點之間排序緩存的,在本機找不到會自動去隔壁拉數據。
ats在使用磁盤的時候不使用文件概念,因此能夠直接使用裸盤(若是你使用文件,也只有一個大文件),ats會本身安排對磁盤的使用方式和數據的組織。
概念:
代理:Http請求並不必定要所有從server獲取,能夠在靠近用戶的機房緩存。尤爲是圖片視頻等資源,這個緩存過程叫作代理。
新鮮度:代理必需要保證緩存的數據是當前最新的,如何與上游的服務器確認是一個專門的話題。HTTP協議自己有提供一些頭部來控制緩存新鮮度。例如max-age、last-modified、expires、date等。ats根據這些頭部和用戶的配置計算一個對象的新鮮度,決定是否要,何時去server段拉取(快要過時的時候去拉取叫fuzz Revalidation)。
緩存控制:能夠控制有的不緩存、當上遊服務器出現擁塞的時候中止拉取、同一個url緩存不一樣的版本。
緩存層級:cache自己也是能夠分層的,就像CPU的一級緩存、二級緩存的概念。在ats中這個概念叫作parent,每一個cache能夠有sibling也能夠有parent,cache在本地查不到,或者在本地的集羣查不到,就能夠去parent去查,parent查不到再回源到後臺server查詢。這些緩存之間還可使用ICP協議(緩存控制協議)查查詢parent或者sibling中的緩存狀態,以便更新本身的緩存。
關鍵字:
l 裸盤:ats的cache支持硬件存儲,不但支持文件系統的文件,還支持裸盤。裸盤支持在linux中有被移除的可能,由於直接訪問磁盤能夠經過O_DIRECT替代。裸盤其實就是不使用文件系統的磁盤,因爲沒有文件系統天然也沒有文件的概念。在內核中是直接走sd驅動,電梯層,到scsi到磁盤的,不須要走文件系統層和緩存層。O_DIRECT也是同樣。
l cache span:一塊連續的物理存儲空間,通常是一個磁盤。
l cache volumn:一個邏輯和業務上的存儲空間,能夠橫跨多個cache span。這就像lvm橫跨多個物理磁盤劃分的邏輯分區。
l cache strip:位於cache span(volumn)上的一條一條的存儲帶。數據都是組織在cache strip中。
l cache ID、cache key:cache key惟一的標示一個緩存對象,通常以url表示,cache ID則是從cache key計算得來的128位的MD5值。
l directory:在cache strip中的數據是由directory組織的。一個cache strip中有多個directory,每一個directory中有多個條目。每個directory都對應一個cache,由cache id索引。但directory只是cache的一個索引,經過directory能夠找到cache在磁盤中的信息和實體。而全部的directory都是加載到內存的,因此若是一次cache查詢結果是miss,就不須要磁盤(經過url計算獲得cache id,可是查詢內存發現該cache id沒有對應directory),就能夠返回。因此directory的存在讓miss過程加速,可是若是找到了directory,每個cache查詢都須要接下來讀取磁盤。值得注意的是,內存中只有directory,不包含實體,而且directory的大小是固定的,磁盤大下也是固定的,只要程序啓動就會盡量多的建立最多的directory,因此程序運行的過程當中ats的內存需求是不會增長的(由於能夠支持的緩存數是固定的,每條緩存在內存中的記錄大小也是固定的)。
l segment、bucket: 並非strip下面就是並排的一片directory,這些directory也是組織的。4個directory是一個bucket,多個bucket是一個segment。在每一個strip的頭部都有一個空閒列表,裏面是每一個segment的directory空閒列表,也就是說又多少個segment在strip的頭部就有多少個列表。事實上,cache ID定位的並非directory,而是bucket,strip的free list也不包含每一個bucket的第一個directory,而是順序的包含第4個、第3個、第2個。如此,來了一個cache object的cache ID(128位),就能夠定位到某個bucket,而後查看該bucket的第一個directory是否是used,若是used說明整個bucket都滿了(只有後面3個都用完了纔會用第1個),這個cache object就添加失敗了。不然就會順序的從4/3/2/1開始使用。因此,綜上能夠看出,bucket其實是一個哈希桶,用來出來哈希函數的碰撞狀況,只給出了4個,說明只能處理4個cache ID一致的狀況。因此segment和bucket這兩種組織結構的引入,是爲了解決管理問題。
l content:咱們知道directory只是元數據,是要常駐內存的,存儲了cache的索引。因此能夠根據directory判斷一個cache是否存在。若是發現了對應的directory,就得去取directory對應的cache的真實內容,這個內容就是放在content裏的,位置由directory指明。directory的數目是動態計算出來的,總大小除以平均一個對象的大小就能夠得到,平均一個對象的大小能夠經過proxy.config.cache.min_average_object_size進行設置,從而控制directory的數目。content的大小是動態的,也是有限的,因此當content滿的時候會自動從開頭開始覆蓋。可是並不會更新directory。直到下一次讀取到directory的時候纔會發現內容不存在,從而更新directory。這裏能夠帶來的一個問題是,經過查看directory的統計值獲得的結果是不許確的,而且一旦跑滿數據量一直滿的。
l fragment:因爲ats的並行性,不可能一會兒存儲太多的連續數據。因此大文件必然要分片(不然併發的來不少大文件緩存請求將沒法應對)。咱們知道directory裏面會指出數據再content中的位置,這裏指出的只是該cache的第一個fragment,在這個fragment的頭部又不少信息,包括其餘的fragment到哪裏去找,還包括其餘的同名版本的存儲directory(例如同一個url的png、jpg版本)
l SPDY:用戶與同一個IP的http通訊,不管是否是同一個網站,都複用一個tcp鏈接。這在大部分狀況下是沒用的,可是在用戶使用的代理的時候就用戶大了。由於用戶的全部http請求都是發到代理去的,使用這個協議能夠一成天都只使用一個tcp鏈接跑http,每一個網戰的http流只是tcp流裏面的一個stream。這對提供代理效率和減輕代理和客戶端負擔有很大的提升。
集羣
多個cache能夠配置爲集羣,完整的集羣模式包含配置文件統一,和節點數據的交互。集羣中的每一個節點的配置文件是同樣的,因此配置文件中不要出現本機的IP。在配置爲集羣模式後(這個須要每臺機器單獨配置),對任何一個節點的配置修改會被自動的同步到其餘節點。同步配置使用多播,交換數據使用單播。
核心代碼在iocore裏面,iocore裏面按照大功能分爲了以下的幾個模塊。
這就要從trafficserver的架構提及了。這幾個目錄幾乎就是traffic server的關鍵字:異步(aio)、緩存(cache)、集羣支持(cluster)、域名解析(dns)、事件系統(eventsysytem)、上游配置(hostdb)、網絡(net)。
網絡與nginx的對比:http://www.cnblogs.com/liushaodong/archive/2013/02/26/2933535.html
除了提供核心程序功能,程序須要入口,入口通常是一個啓動server的主程序和若干的管理程序,管理程序都在cmd目錄下,每個目錄是一個管理程序:
主程序位於proxy目錄下的Main.cc(.cc後綴的是C++文件的glibc後綴表示)。
主程序名稱是traffic_server,
traffic_manager:爲traffic_ctl提供服務
traffic_cop:獨立的監控程序,監控traffic_server和traffic_manager的職責和內存交換空間使用狀況,發現異常重啓進程。
traffic_crashlog:由traffic_server進程啓動,在traffic_server崩潰的時候打印一個崩潰報告到log目錄。
traffic_ctl:在線配置一些traffic_server能夠配置的參數
traffic_logcat:將trafficserver的二進制log文件轉變成可讀的ASCII log
traffic_logstats:trafficserver的log分析工具
traffic_via:能夠配置proxy.config.http.insert_request_via_str、proxy.config.http.insert_response_via_str兩個參數使得全部的數據的http頭部都攜帶VIA信息(表示cache狀態,能夠看出是從哪裏拿來的),wget這個文件就會在http頭部看到這個信息,而這個信息是被traffic server編碼過的,使用traffic_via命令能夠將這個信息解碼就能夠看到緩存的獲取路徑。
traffic_sac:standalonecollator。日誌收集器,用在traffic server集羣中。能夠用來收集各個節點的日誌集中到本機進行處理。一個節點能夠不安裝traffic server,只安裝sac能夠發揮更大的日誌能力。
tspush:不須要用戶請求能夠直接使用這個命令將內容投遞到traffic server的cache中,使用這個命令須要打開proxy.config.http.push_method_enabled 選項
tsxs:插件編譯程序。用來編譯和安裝插件。
traffic_top:一個方便的查看當前trafficserver內部狀態的程序。要編譯這個必需要有libncurses5-dev庫,不然會靜悄悄不安裝。
Trafficserver雖然大部分狀況跑在linux上,可是倒是跨平臺的。通常的操做系統都提供了網絡訪問的方式,可是並無提供大量併發網絡訪問的方式(或許往後操做系統的API能夠直接提供這個功能),因此處理大量併發須要程序本身來(有的編程語言內部封裝了這部分邏輯,例如golang,就省了程序的事了)。目前處理這個問題的最經常使用辦法就是上層抽象協程。
除了網絡訪問,操做系統通常也不提供特別易用的事件系統、dns系統、緩存系統、集羣系統等接口。然而這些都是traffic server核心功能所要依賴的底層服務。Traffic server的應對辦法是將這些服務封裝,主要邏輯所有基於封裝的服務,而不是操做系統的API(這裏就不得不說操做系統和glibc的API不與時俱進了。。。還得別人還得本身搞)。
必需要理解的是trafficserver是個程序,主要的業務是無數的transaction,每一個transaction都是一個用戶的http鏈接處理,不只包含了用戶的tcp鏈接,還包含了traffic server與後端的通訊和本地操做等。一個transaction只是用戶一個tcp鏈接上執行的一次事務,還有一個session概念,是一個client和server之間tcp概念上的鏈接。一個session能夠包括不少個transaction。對用戶來講,一個request和response是一個transaction。