1. 程式人生 > >traffic server文件目錄

traffic server文件目錄

tsp 哈希 socks 級別 stats 調用方法 可讀的 重復 回調函數

功能:

Trafficserver的主要功能是緩存,當然你也可以用它來做純粹的反向代理(像通常用nginx那樣)。通常切入一個龐大的系統的最好方式是看如何使用,使用traffic server的主要入口有兩個:配置文件和插件。所有使用者都需要配置文件,高級使用者則需要插件。

traffic支持大規模的集群處理,不同於nginx的單點(需要ospf均衡鏈路來做冗余),所有的配置文件可以做到改動一個通知全部。程序根據功能劃分為不同的幾個子程序,有服務運行時使用的程序,也有管理使用的。詳細見下文。

[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.config

n 上遊拉取數據擁塞控制:congestion.config

n 緩存分割與上遊分配:hosting.config

n 劃分不同種類的緩存類型(與hosting.config配合可以實現不同種的數據緩存安排)

n 定義上遊的peer:Icp.config

n 定義可以使用cache的白名單:ip_allow.config

n 緩存可以定義多級,定義級別的配置:parent.config

n 緩存持久化:storage.config

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連接。

cache系統:

使用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不與時俱進了。。。還得別人還得自己搞)。

HTTP事務流程:

必須要理解的是trafficserver是個程序,主要的業務是無數的transaction,每個transaction都是一個用戶的http連接處理,不僅包含了用戶的tcp連接,還包含了traffic server與後端的通信和本地操作等。一個transaction只是用戶一個tcp連接上執行的一次事務,還有一個session概念,是一個client和server之間tcp概念上的連接。一個session可以包括很多個transaction。對用戶來說,一個request和response是一個transaction。

traffic server文件目錄