天天看点

Varnish的负载均衡、动静分离

一、Varish的简介

    Varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang 使用3台Varnish代替了原来的12台Squid,性能比以前更好。

    在当前主流的Web架构中,Cache担任着越来越重要的作用。常见的基于浏览器的C/S架构,Web Cache更是节约服务器资源的关键。而最近几年由FreeBSD创始人之一Kamp开发的varnish更是一个不可多得的Web Cache Server。严格意义上说,Varnish是一个高性能的反向代理软件,只不过与其出色的缓存功能相比,企业更愿意使用其搭建缓存服务器。同时,由于其工作在Web Server的前端,有一部分企业已经在生产环境中使用其作为旧版本的squid的替代方案,以在相同的服务器成本下提供更好的缓存效果,Varnish更是作为CDN缓存服务器的可选服务之一。

二、关于Varnish

1、varnish系统架构

varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)。

Management进程

    主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。

Child进程包含多种类型的线程,常见的如:

    Acceptor线程:接收新的连接请求并响应;

    Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多;

    Expiry线程:从缓存中清理过期内容;

Varnish依赖“工作区(workspace)”以降低线程在申请或修改内存时出现竞争的可能性。在varnish内部有多种不同的工作区,其中最关键的当属用于管理会话数据的session工作区。

2、varnish日志

为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此,如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个worker线程都使用了日志数据缓存。

共享内存日志大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示。

3、VCL

Varnish Configuration Language (VCL)是varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等。使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义。

VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成。

4、varnish的后端存储

varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:

(1)file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果条件允许);

(2)malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;

(3)persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;

varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此,file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以,其仅适用于有着巨大缓存空间的场景。

选择使用合适的存储方式有助于提升系统性,从经验的角度来看,建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之,file存储将有着更好的性能的表现。然而,需要注意的是,varnishd实际上使用的空间比使用-s选项指定的缓存空间更大,一般说来,其需要为每个缓存对象多使用差不多1K左右的存储空间,这意味着,对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外,为了保存数据结构等,varnish自身也会占去不小的内存空间。

为varnishd指定使用的缓存类型时,-s选项可接受的参数格式如下:

malloc[,size] 或

file[,path[,size[,granularity]]] 或

persistent,path,size {experimental}

file中的granularity用于设定缓存空间分配单位,默认单位是字节,所有其它的大小都会被圆整。

三、安装varnish

官方最新版本:Varnish Cache 4.0.1

Varnish学习需要注意的要素:

    1、Varnish要安装在64的系统上

    2、Varnish使用内存做缓存大小为2G,基本就可以了;无论是memcache还是varnish基于内存做缓存都不宜太大,太大没有好处,它有一个临界值,如果缓存设置太小,那么数据缓存会频繁被清除掉;如果缓存设置太大的,那么缓存会永久存放,有些过期的也不会被清除掉,并且数据过多的查找起来也慢。建议Varnish缓存设置大小为1G-2G之间就可以了。

1、yum安装varnish

1

2

<code>[root@Varnish ~]</code><code># rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-3.0.el6.rpm</code>

<code>[root@Varnish ~]</code><code># yum -y install varnish</code>

2、Varnish的配置文件说明

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<code>[root@Varnish ~]</code><code># grep -v "^#" /etc/sysconfig/varnish |sed '/^$/d'</code>

<code>NFILES=131072                               </code><code># 最大打开文件数65536*2{ulimit -n}</code>

<code>MEMLOCK=82000                               </code><code># 锁定使用多大的共享内存来保存日志信息,默认为82M</code>

<code>NPROCS=</code><code>"unlimited"</code>                          <code># 最大的线程数,默认无限制</code>

<code># DAEMON_COREFILE_LIMIT="unlimited"            # 进程核心转储所使用的内存空间,unlimited表示无上限</code>

<code>RELOAD_VCL=1                                </code><code># 设置为1可以使用restart自动加载vcl配置文件</code>

<code>VARNISH_VCL_CONF=</code><code>/etc/varnish/default</code><code>.vcl   </code><code># 定义vcl配置文件</code>

<code>VARNISH_LISTEN_PORT=6081                    </code><code># 定义varnish服务监听端口</code>

<code>VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1      </code><code># 定义允许进行进程管理地址</code>

<code>VARNISH_ADMIN_LISTEN_PORT=6082              </code><code># 定义管理进程监听端口</code>

<code>VARNISH_SECRET_FILE=</code><code>/etc/varnish/secret</code>     <code># 定义秘钥和签名认证文件</code>

<code>VARNISH_MIN_THREADS=50                      </code><code># 定义varnish启动时最小线程数</code>

<code>VARNISH_MAX_THREADS=1000                    </code><code># 定义varnish启动时最大线程数</code>

<code>VARNISH_THREAD_TIMEOUT=120                  </code><code># 定义varnish线程响应超时时间</code>

<code>VARNISH_STORAGE_FILE=</code><code>/var/lib/varnish/varnish_storage</code><code>.bin   </code><code># 定义varnish的缓存文件</code>

<code>VARNISH_STORAGE_SIZE=1G                                     </code><code># 定义缓存使用文件大小,单位:k/M/G/T</code>

<code>VARNISH_STORAGE=</code><code>"file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"</code>  <code># 使用文件缓存</code>

<code>#VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}"                       # 使用内存缓存;malloc</code>

<code>VARNISH_TTL=120                                                         </code><code># 如果后端服务器没有设置数据缓存多长时间,则默认为120秒</code>

<code>DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \        </code><code># 变量调用</code>

<code>             </code><code>-f ${VARNISH_VCL_CONF} \</code>

<code>             </code><code>-T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \</code>

<code>             </code><code>-t ${VARNISH_TTL} \</code>

<code>             </code><code>-w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \</code>

<code>             </code><code>-u varnish -g varnish \</code>

<code>             </code><code>-S ${VARNISH_SECRET_FILE} \ </code><code>#前端和后端在通信的过程中实现加密和签名的迷药文件,防止别人篡改数据的。</code>

<code>             </code><code>-s ${VARNISH_STORAGE}"</code>

3、Varnish的VCL配置说明

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

<code>[root@Varnish ~]</code><code># cat /etc/varnish/default.vcl           </code>

<code>#定义后端默认的服务器</code>

<code>backend default {</code>

<code>  </code><code>.host = </code><code>"127.0.0.1"</code><code>; </code>

<code>  </code><code>.port = </code><code>"80"</code><code>;        </code>

<code>}             </code>

<code>#定义一个vcl_recv函数          </code>

<code>sub vcl_recv {</code>

<code>#req.restarts可以解释为如果客户端第一次开始请求时,</code>

<code>#如果请求的http中含有X-Forwarded-For信息,不管如何都在该信息后面附加客户端的ip地址信息;</code>

<code>#若不含有X-Forwarded-For信息,则直接附加client.ip地址信息。</code>

<code>#X-Forwarded-For通常表示代理服务器的地址</code>

<code>#为什么要补充client.ip呢?因为varnish做了反向代理,为了使后端服务器记录客户端的ip地址而非varnish的地址</code>

<code>    </code><code>if</code> <code>(req.restarts == 0) {</code>

<code>      </code><code>if</code> <code>(req.http.x-forwarded-</code><code>for</code><code>) {</code>

<code>          </code><code>set</code> <code>req.http.X-Forwarded-For =</code>

<code>              </code><code>req.http.X-Forwarded-For + </code><code>", "</code> <code>+ client.ip;</code>

<code>      </code><code>} </code><code>else</code> <code>{</code>

<code>          </code><code>set</code> <code>req.http.X-Forwarded-For = client.ip;</code>

<code>      </code><code>}</code>

<code>    </code><code>}</code>

<code>#定义http请求的方法;如果客户端请求的http的方法不是GET/HEAD/PUT/POST/TRAGE/OPTIONS/DELETE,</code>

<code>#那么我们的varnish就不会去把请求传递给varnish的vcl_hash,直接交给pipe,表示varnish无法理解或者认为是非法的请求。</code>

<code>    </code><code>if</code> <code>(req.request != </code><code>"GET"</code> <code>&amp;&amp;</code>

<code>      </code><code>req.request != </code><code>"HEAD"</code> <code>&amp;&amp;</code>

<code>      </code><code>req.request != </code><code>"PUT"</code> <code>&amp;&amp;</code>

<code>      </code><code>req.request != </code><code>"POST"</code> <code>&amp;&amp;</code>

<code>      </code><code>req.request != </code><code>"TRACE"</code> <code>&amp;&amp;</code>

<code>      </code><code>req.request != </code><code>"OPTIONS"</code> <code>&amp;&amp;</code>

<code>      </code><code>req.request != </code><code>"DELETE"</code><code>) {</code>

<code>        </code><code>/* Non-RFC2616 or CONNECT </code><code>which</code> <code>is weird. */</code>

<code>        </code><code>return</code> <code>(pipe);</code>

<code>#如果请求的方法不是GET,也不是HEAD,那么有可能就是PUT,POST,这些都是上传数据的,</code>

<code>#对于上传的数据,我们没有必要缓存,直接跟后端服务器交互。</code>

<code>    </code><code>if</code> <code>(req.request != </code><code>"GET"</code> <code>&amp;&amp; req.request != </code><code>"HEAD"</code><code>) {</code>

<code>        </code><code>/* We only deal with GET and HEAD by default */</code>

<code>        </code><code>return</code> <code>(pass); </code><code>#不查找缓存,直接从后端服务器获取数据</code>

<code>#如果请求的内容中包括Authorization授权的,包括Cookie认证的,这些都是用户的敏感数据,一定不能缓存的。</code>

<code>    </code><code>if</code> <code>(req.http.Authorization || req.http.Cookie) {</code>

<code>        </code><code>/* Not cacheable by default */</code>

<code>        </code><code>return</code> <code>(pass);</code>

<code>    </code><code>return</code> <code>(lookup);   </code><code>#lookup表示从缓存中查找</code>

<code>}            </code>

<code>    </code> 

<code>#从后端服务器fetch数据</code>

<code>sub vcl_pass {</code>

<code>    </code><code>return</code> <code>(pass);</code>

<code>}</code>

<code>sub vcl_hash {                    </code><code>#定义vcl_hash函数</code>

<code>    </code><code>hash_data(req.url);         </code><code>#默认是根据用户请求的url做hash</code>

<code>    </code><code>if</code> <code>(req.http.host) {      </code><code>#如果用户的请求http的首部中有host,那么就对此做hash</code>

<code>        </code><code>hash_data(req.http.host);</code>

<code>    </code><code>} </code><code>else</code> <code>{</code>

<code>        </code><code>hash_data(server.ip);   </code><code>#否则根据服务器端的地址做hash</code>

<code>    </code><code>return</code> <code>(</code><code>hash</code><code>);             </code><code>#最终返回hash数据</code>

<code>#如果命中的则直接从本地缓存中返回数据给用户</code>

<code>sub vcl_hit {</code>

<code>    </code><code>return</code> <code>(deliver);</code>

<code>#如果没有命中,则从后端服务器取数据</code>

<code>sub vcl_miss {</code>

<code>    </code><code>return</code> <code>(fetch);</code>

<code>#如果没有命中,那么从后端服务器取数据应该怎样取呢?</code>

<code>#在响应客户端之前,如果ttl头部值小于等于0秒,表示缓存已经过期了,</code>

<code>#并且其中包含有"Set-Cookie","Vary"这些字段,那么就直接设定这些过期的缓存信息的缓存期限为120秒</code>

<code>#如果其中没有这些字段的话就直接缓存下来了。</code>

<code>sub vcl_fetch {</code>

<code>    </code><code>if</code> <code>(beresp.ttl &lt;= 0s ||             </code>

<code>        </code><code>beresp.http.Set-Cookie ||     </code>

<code>        </code><code>beresp.http.Vary == </code><code>"*"</code><code>) {</code>

<code>              </code><code>/*</code>

<code>               </code><code>* Mark as </code><code>"Hit-For-Pass"</code> <code>for</code> <code>the next 2 minutes</code>

<code>               </code><code>*/</code>

<code>              </code><code>set</code> <code>beresp.ttl = 120 s;</code>

<code>              </code><code>return</code> <code>(hit_for_pass);</code>

<code>sub vcl_deliver {</code>

<code>#客户端请求某个页面,如果服务器上不存在这个页面,就请求错误</code>

<code>#对于后端服务器没有这个文件的,直接交由varnish响应一个错误信息</code>

<code>sub vcl_error {</code>

<code>    </code><code>set</code> <code>obj.http.Content-Type = </code><code>"text/html; charset=utf-8"</code><code>;</code>

<code>    </code><code>set</code> <code>obj.http.Retry-After = </code><code>"5"</code><code>;</code>

<code>    </code><code>synthetic {"</code>

<code>&lt;?xml version=</code><code>"1.0"</code> <code>encoding=</code><code>"utf-8"</code><code>?&gt;</code>

<code>&lt;!DOCTYPE html PUBLIC </code><code>"-//W3C//DTD XHTML 1.0 Strict//EN"</code>

<code> </code><code>"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"</code><code>&gt;</code>

<code>&lt;html&gt;</code>

<code>  </code><code>&lt;</code><code>head</code><code>&gt;</code>

<code>    </code><code>&lt;title&gt;</code><code>"} + obj.status + "</code> <code>" + obj.response + {"</code><code>&lt;</code><code>/title</code><code>&gt;</code>

<code>  </code><code>&lt;</code><code>/head</code><code>&gt;</code>

<code>  </code><code>&lt;body&gt;</code>

<code>    </code><code>&lt;h1&gt;Error </code><code>"} + obj.status + "</code> <code>" + obj.response + {"</code><code>&lt;</code><code>/h1</code><code>&gt;</code>

<code>    </code><code>&lt;p&gt;</code><code>"} + obj.response + {"</code><code>&lt;</code><code>/p</code><code>&gt;</code>

<code>    </code><code>&lt;h3&gt;Guru Meditation:&lt;</code><code>/h3</code><code>&gt;</code>

<code>    </code><code>&lt;p&gt;XID: </code><code>"} + req.xid + {"</code><code>&lt;</code><code>/p</code><code>&gt;</code>

<code>    </code><code>&lt;hr&gt;</code>

<code>    </code><code>&lt;p&gt;Varnish cache server&lt;</code><code>/p</code><code>&gt;</code>

<code>  </code><code>&lt;</code><code>/body</code><code>&gt;</code>

<code>&lt;</code><code>/html</code><code>&gt;</code>

<code>"};</code>

<code>sub vcl_init {</code>

<code>      </code><code>return</code> <code>(ok);</code>

<code>sub vcl_fini {</code>

四、Varnish状态引擎以及工作原理说明

<a href="http://s3.51cto.com/wyfs02/M02/53/7B/wKioL1Rot_TCI59vAAH002Hq3FI410.jpg" target="_blank"></a>

<code>vcl_recv:用于接收到用户的请求</code>

<code>在vcl_hit引擎中可以调用</code><code>return</code><code>(pipe)指令和调用</code><code>return</code><code>(lookup)指令和调用</code><code>return</code><code>(pass)指令。</code>

<code>如果不检查缓存;</code>

<code>    </code><code>调用的是</code><code>return</code><code>(pipe)指令,然后由vcl_pipe引擎直接交给后端服务器进行处理</code>

<code>如果是检查缓存;</code>

<code>    </code><code>调用</code><code>return</code><code>(lookup)指令,检查缓存,看缓存是否命中,需自行定义如何</code>

<code>检查缓存</code>

<code>    </code><code>调用</code><code>return</code><code>(pass)指令,则将请求送给vcl_pass进行处理</code>

<code>vcl_pipe:用于把用户的请求接进来,然后建立一个管道直接交给后端服务器</code>

<code>    </code><code>在vcl_pipe引擎中可以调用</code><code>return</code><code>(pipe)指令</code>

<code>    </code><code>调用</code><code>return</code><code>(pipe)指令则建立一个与后端服务器的管道</code>

<code>vcl_hash:用于自行定义其它缓存的机制</code>

<code>    </code><code>在vcl_hash引擎中可以调用</code><code>return</code><code>(</code><code>hash</code><code>)指令</code>

<code>    </code><code>调用</code><code>return</code><code>(</code><code>hash</code><code>)指令,则通过</code><code>hash</code><code>键值对进行判断,是否命中</code>

<code>vcl_hit:用于表示缓存命中</code>

<code>在vcl_hit引擎中可以调用</code><code>return</code><code>(pass)指令和调用</code><code>return</code><code>(delive)指令</code>

<code>    </code><code>如果是调用</code><code>return</code><code>(pass)指令,则将请求送给vcl_pass进行处理</code>

<code>        </code><code>{此情况发生在当自定义的缓存为1个小时,但未满一个小时,所设置的缓存已经发生变化则需要用vcl_pass}</code>

<code>    </code><code>如果是调用</code><code>return</code><code>(delive)指令,则从缓存中直接取出后由vcl_deliver返回给用户</code>

<code>vcl_miss:用于表示缓存未命中</code>

<code>在vcl_miss引擎中可以调用</code><code>return</code><code>(pass)指令和调用</code><code>return</code><code>(fetch)指令</code>

<code>    </code><code>如果是调用</code><code>return</code><code>(fetch)指令,则将请求送给vcl_fetch进行处理</code>

<code>vcl_pass:用于给命中引擎和未命中引擎提供处理机制</code>

<code>在vcl_pass引擎中可以调用</code><code>return</code><code>(fetch)指令</code>

<code>    </code><code>调用</code><code>return</code><code>(fetch)指令,则将请求送给vcl_fetch进行处理</code>

<code>vcl_fetch:用于到后端服务器去取数据</code>

<code>在vcl_fetch引擎中可以调用</code><code>return</code><code>(delive)指令和调用</code><code>return</code><code>(pass)指令</code>

<code>    </code><code>如果是调用</code><code>return</code><code>(delive)指令,则把后端取的数据保存在缓存中</code>

<code>    </code><code>如果是调用</code><code>return</code><code>(pass)指令,则不把后端取的数据保存在缓存中</code>

<code>vcl_deliver:用于从缓存中取数据返回给用户</code>

<code>vcl_error:用于由varnish直接构建错误响应报文</code>

<a href="http://s3.51cto.com/wyfs02/M00/53/7B/wKioL1RouYDg7sj-AAZBXldc0_0976.jpg" target="_blank"></a>

************************

<code>vcl_recv:用户请求到达varnish之后,varnish就要vcl函数做一些验证和处理操作。</code>

<code>    </code><code>pipe:管道 送给其它的进程或其它的机制来处理,一般用的比较少。</code>

<code>    </code><code>pass:不查找本地缓存,直接从后端服务器获取数据。</code>

<code>    </code><code>lookup:查找,从本地缓存中查找,</code>

<code>        </code><code>vcl_hash:定义对用户查找的链接做vcl运算并比较的,因此我们用用户请求的url链接根据自已定义的vcl方式做</code><code>hash</code><code>计算以后,就会得到</code><code>hash</code><code>码;</code>

<code>                 </code><code>为了使缓存中的数据查找效率高,这些缓存中的数据都是以键值对的方式存储的,key(url)和value(object)</code>

<code>                 </code><code>这里的key是用户请求的url,value是用户请求的文件内容,我们叫缓存对象。</code>

<code>                 </code><code>如果直接用url来做key,那么查找起来是十分缓慢的,往往都是把url做</code><code>hash</code><code>编码,可以指定</code><code>hash</code><code>编码的算法。得到</code><code>hash</code><code>码。      </code>

<code>        </code><code>Is the object </code><code>in</code> <code>cache?:如果用得到的</code><code>hash</code><code>码给现存缓存列表中的key做比较,如果有一样的则就命中缓存了。否则缓存没有命中。</code>

<code>            </code><code>vcl_miss:</code>

<code>                </code><code>vcl_pass:</code>

<code>                    </code><code>{</code>

<code>                    </code><code>(vcl_pass)pass:如果没有命中,多一步验证措施</code>

<code>                    </code><code>(vcl_pass)fetch:到后端服务器取数据</code>

<code>                    </code><code>}</code>

<code>            </code><code>vcl_hit:</code>

<code>                </code><code>{</code>

<code>                </code><code>(vcl_hit)pass:尽管命中的也不在缓存中返回,而是从后端服务器取数据,因为这些数据可能是私有的,比如登陆账户、密码,认证加密文件</code>

<code>                </code><code>(vcl_hit)deliver:表示如果命中了并想数据缓存下来或者说把数据做缓存了,在或者说从缓存中取数据了。</code>

<code>                </code><code>}</code>

<code>                </code><code>deliver:</code>

<code>                </code> 

<code>            </code><code>Fetch object from backend:表示从后端服务器取数据</code>

<code>                </code><code>vcl_fetch</code>

<code>                    </code><code>Cache(deliver):先缓存在返回给用户</code>

<code>                    </code><code>Dont't cache(pass):不缓存直接返回给用户</code>

<code>                </code><code>vcl_deliver:</code>

五、Varnish的一些补充命令说明

1、启动varnish命令

<code># /etc/init.d/varnish start</code>

2、查看varnish监听的端口

<code># netstat -tnlp |grep varnish</code>

<code>tcp        0      0 0.0.0.0:6081                0.0.0.0:*                   LISTEN      1397</code><code>/varnishd</code>       

<code>tcp        0      0 127.0.0.1:6082              0.0.0.0:*                   LISTEN      1396</code><code>/varnishd</code>       

<code>tcp        0      0 :::6081                     :::*                        LISTEN      1397</code><code>/varnishd</code>

3、varnishadm的管理工具命令

<code>[root@Varnish ~]</code><code># varnishadm -h</code>

<code>varnishadm: invalid option -- </code><code>'h'</code>

<code>usage: varnishadm [-n ident] [-t timeout] [-S secretfile] -T [address]:port </code><code>command</code> <code>[...]</code>

<code>    </code><code>-n is mutually exlusive with -S and -T</code>

<code>[root@Varnish ~]</code><code># varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret    # 登录管理命令行</code>

<code>200        </code>

<code>-----------------------------</code>

<code>Varnish Cache CLI 1.0</code>

<code>Linux,2.6.32-358.el6.x86_64,x86_64,-sfile,-smalloc,-hcritbit</code>

<code>varnish-3.0.6 revision 1899836</code>

<code>Type </code><code>'help'</code> <code>for</code> <code>command</code> <code>list.</code>

<code>Type </code><code>'quit'</code> <code>to close CLI session.</code>

<code>varnish&gt; help       </code><code>#查看帮助命令</code>

<code>help [</code><code>command</code><code>]</code>

<code>ping</code> <code>[timestamp]</code>

<code>auth response</code>

<code>quit</code>

<code>banner</code>

<code>status</code>

<code>start</code>

<code>stop</code>

<code>vcl.load &lt;configname&gt; &lt;filename&gt;</code>

<code>vcl.inline &lt;configname&gt; &lt;quoted_VCLstring&gt;</code>

<code>vcl.use &lt;configname&gt;</code>

<code>vcl.discard &lt;configname&gt;</code>

<code>vcl.list</code>

<code>vcl.show &lt;configname&gt;</code>

<code>param.show [-l] [&lt;param&gt;]</code>

<code>param.</code><code>set</code> <code>&lt;param&gt; &lt;value&gt;</code>

<code>panic.show</code>

<code>panic.</code><code>clear</code>

<code>storage.list</code>

<code>backend.list</code>

<code>backend.set_health matcher state</code>

<code>ban.url &lt;regexp&gt;</code>

<code>ban &lt;field&gt; &lt;operator&gt; &lt;arg&gt; [&amp;&amp; &lt;field&gt; &lt;oper&gt; &lt;arg&gt;]...</code>

<code>ban.list</code>

<code>varnish&gt; </code><code>ping</code>                                   <code># 测试ping命令</code>

<code>PONG 1416045552 1.0</code>

<code>varnish&gt; vcl.load d1 </code><code>/etc/varnish/default</code><code>.vcl </code><code># 加载编译新配置, d1是配置名,default.vcl是配置文件</code>

<code>VCL compiled.</code>

<code>varnish&gt; vcl.list                               </code><code># 列出所有的配置</code>

<code>active          0 boot</code>

<code>available       0 d1</code>

<code>varnish&gt; vcl.use d1                                </code><code># 使用配置,需指定配置名,当前使用的配置以最后一次vcl.use为准</code>

<code>varnish&gt; backend.list                           </code><code>#查看配置文件的配置信息</code>

<code>Backend name                   Refs   Admin      Probe</code>

<code>default(127.0.0.1,,80)         2      probe      Healthy (no probe)</code>

<code>varnish&gt; storage.list                           </code><code>#查看储存列表信息</code>

<code>Storage devices:</code>

<code>    </code><code>storage.Transient = malloc</code>

<code>    </code><code>storage.s0 = </code><code>file</code>

六、Varnish检测后端主机的健康状态

Varnish可以检测后端主机的健康状态,在判定后端主机失效时能自动将其从可用后端主机列表中移除,而一旦其重新变得可用还可以自动将其设定为可用。为了避免误判,Varnish在探测后端主机的健康状态发生转变时(比如某次探测时某后端主机突然成为不可用状态),通常需要连续执行几次探测均为新状态才将其标记为转换后的状态。

每个后端服务器当前探测的健康状态探测方法通过.probe进行设定,其结果可由req.backend.healthy变量获取,也可通过varnishlog中的Backend_health查看或varnishadm的debug.health查看。

backend web1 {

.host = "www.allentuns.com";

.probe = {

.url = "/.healthtest.html";

.interval = 1s;

.window = 5;

.threshold = 2;

}

.probe中的探测指令常用的有:

(1) .url:探测后端主机健康状态时请求的URL,默认为“/”;

(2) .request: 探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;比如:

.request =

"GET /.healthtest.html HTTP/1.1"

"Host: www.allentuns.com"

"Connection: close";

(3) .window:设定在判定后端主机健康状态时基于最近多少次的探测进行,默认是8;

(4) .threshold:在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行;默认是3;

(5) .initial:Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;

(6) .expected_response:期望后端主机响应的状态码,默认为200;

(7) .interval:探测请求的发送周期,默认为5秒;

(8) .timeout:每次探测请求的过期时长,默认为2秒;

因此,如上示例中表示每隔1秒对此后端主机www.allentuns.com探测一次,请求的URL为http://www.allentuns.com/.healthtest.html,在最近5次的探测请求中至少有2次是成功的(响应码为200)就判定此后端主机为正常工作状态。

如果Varnish在某时刻没有任何可用的后端主机,它将尝试使用缓存对象的“宽容副本”(graced copy),当然,此时VCL中的各种规则依然有效。因此,更好的办法是在VCL规则中判断req.backend.healthy变量显示某后端主机不可用时,为此后端主机增大req.grace变量的值以设定适用的宽容期限长度。

七、Varnish的负载均衡和动静分离配置文件

在实际生产环境中对后端server进行健康状态检查的时候;

静态的在网页根目录创建一个test.html检测页面,动态的在网页根目录先创建一个test.jsp的检测页面

<code># Configure VCL</code>

<code>probe static_chk {    </code><code>#静态网页的健康状态检查</code>

<code>        </code><code>.url = </code><code>"/test.html"</code><code>;</code>

<code>        </code><code>.interval = 2s;</code>

<code>        </code><code>.timeout = 2s;</code>

<code>        </code><code>.expected_response = 200;</code>

<code>probe dynamic_chk {    </code><code>#动态网页的健康状态检查</code>

<code>        </code><code>.url = </code><code>"/test.php"</code><code>;</code>

<code>backend apache01 {    </code><code>#静态请求负载均衡1</code>

<code>        </code><code>.host = </code><code>"192.168.0.108"</code><code>;</code>

<code>        </code><code>.port = </code><code>"80"</code><code>;</code>

<code>                </code><code>.probe = static_chk;</code>

<code>backend apache02 {    </code><code>#静态请求负载均衡2</code>

<code>        </code><code>.host = </code><code>"192.168.0.110"</code><code>;</code>

<code>backend nginx01 {    </code><code>#动态请求分发地址</code>

<code>        </code><code>.host = </code><code>"192.168.0.100"</code><code>;</code>

<code>                </code><code>.probe = dynamic_chk;</code>

<code>director myload random {    </code><code>#分发器和调度算法</code>

<code>        </code><code>.retries = 2;</code>

<code>        </code><code>{</code>

<code>                </code><code>.backend = apache01;</code>

<code>                </code><code>.weight = 1;</code>

<code>        </code><code>}</code>

<code>                </code><code>.backend = apache02;</code>

<code>        </code><code>set</code> <code>req.http.X-Forward-For = client.ip;    </code><code>#记录客户端的ip地址</code>

<code>        </code><code>if</code> <code>(req.url ~ </code><code>"\.(html)$"</code> <code>) {</code>

<code>                </code><code>return</code><code>(lookup);</code>

<code>        </code><code>if</code> <code>(req.url ~ </code><code>"\.(php)$"</code><code>) {  </code><code>#如果请求的是php文件则将请求发送给nginx代理的服务器</code>

<code>                </code><code>set</code> <code>req.backend = nginx01;</code>

<code>        </code><code>}</code><code>else</code><code>{</code>

<code>                </code><code>set</code> <code>req.backend = myload; </code><code>#如果请求的是html文件则将请求发送给myload代理的服务器</code>

<code>        </code><code>if</code> <code>(req.request == </code><code>"GET"</code> <code>&amp;&amp; req.url ~ </code><code>"\.(html|jpg|jpeg)$"</code><code>) {</code>

<code>                </code><code>set</code> <code>beresp.ttl = 3600s;</code>

<code>sub vcl_deliver {            </code><code>#记录命中和未命中的变量设定</code>

<code>        </code><code>if</code> <code>(obj.hits &gt; 0) {</code>

<code>                </code><code>set</code> <code>resp.http.X-Cache = </code><code>"HIT from"</code> <code>+ </code><code>" "</code> <code>+ server.ip;</code>

<code>        </code><code>} </code><code>else</code> <code>{</code>

<code>                </code><code>set</code> <code>resp.http.X-Cache = </code><code>"MISS"</code><code>;</code>

<code>        </code><code>return</code><code>(deliver);</code>

好了,就写到这里吧;感觉这篇文章写的很不详细,架构图也没有画,案例也没有一个个演示,直接上的配置文件。最近发现自已越来越懒的。前几天一直学习python,有点学上瘾了。好了,大家晚安。明天周一 都能够有个好心情。下篇博文会继续补充。

     本文转自zys467754239 51CTO博客,原文链接:http://blog.51cto.com/467754239/1577216,如需转载请自行联系原作者