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。