一、varnishd指令
Varnish启动的命令是/usr/local/varnish/sbin/varnishd,此命令参数较多,用法比较复杂,在命令行执行“/usr/local/varnish/sbin/varnishd –h”即可得到varnishd的详细用法,表2-6列出了varnishd常用参数的使用方法和含义。
表1

  1. 命令参数 参数含义
  2. -a address:port 表示varnish对httpd的监听地址及其端口
  3. -b address:port 表示后端服务器地址及其端口
  4. -d 表示使用debug调试模式
  5. -f file 指定varnish服务器的配置文件
  6. -p param=value 指定服务器参数,用来优化varnish性能
  7. -P file Varnish进程PID文件存放路径
  8. -n dir 指定varnish的工作目录
  9. -s kind[,storageoptions] 指定varnish缓存内容的存放方式,常用的方式有:“-s file,<dir_or_file>,<size>”。
  10. 其中“<dir_or_file>”指定缓存文件的存放路径,“<size>”指定缓存文件的大小
  11. -t 指定缺省的TTL值
  12. -T address:port 设定varnish的telnet管理地址及其端口
  13. -w int[,int[,int]] 设定varnish的工作线程数,常用的方式有:
  14. -w min,max
  15. -w min,max,timeout
  16. 例如:-w5,51200,30,这里需要说明下,在varnish2.0版本以后,最小启动的线程数不能设定过大,设置过大,会导致varnish运行异常缓慢。
    -V 显示varnish版本号和版权信息

二、 配置varnish运行脚本
在安装varnish一节中,已经将varnish的管理脚本拷贝到了相应的目录下,这里稍作修改即可使用,首先修改/etc/sysconfig/varnish文件,根据本章的实例,配置好的文件如下:

  1. NFILES=131072
  2. MEMLOCK=82000
  3. DAEMON_OPTS="-a 192.168.12.246:80 \
  4. -T 127.0.0.1:3500 \
  5. -f /usr/local/varnish/etc/vcl.conf \
  6. -u varnish -g varnish \
  7. -w 2,51200,10 \
  8. -n /data/varnish/cache \
  9. -s file, /data/varnish/cache/varnish_cache.data,4G"

这里需要说明的是,缓存文件“varnish_cache.data”在32位操作系统下,最大仅能支持2G,如果需要更大缓存文件则需要安装64为Linux操作系统。
接着需要修改的文件是/etc/init.d/varnish,找到如下行,改为相应的路径即可:

  1. exec="/usr/local/varnish/sbin/varnishd"
  2. prog="varnishd"
  3. config="/etc/sysconfig/varnish"
  4. lockfile="/var/lock/subsys/varnish"

其中,“exec”用于指定varnishd的路径,只需修改为varnish安装路径下对应的varnishd文件即可。“config”用于指定varnish守护进程配置文件路径。
两个文件修改完毕,就可以授权、运行/etc/init.d/varnish脚本了,执行如下:

  1. [root@varnish-server ~]#chmod 755 /etc/init.d/varnish
  2. [root@varnish-server ~]#/etc/init.d/varnish
  3. Usage:/etc/init.d/varnish
  4. {start|stop|status|restart|condrestart|try-restart|reload|force-reload}

从输出可知,此脚本功能强大,可以对varnish进行启动、关闭、查看状态、重启等操作。最后,启动varnish:

  1. [root@varnish-server ~]# /etc/init.d/varnish  start
  2. Starting varnish HTTP accelerator:                         [  OK  ]

三、管理varnish运行日志
varnish是通过内存共享的方式提供日志的,它提供了两种日志输出形式,分别是:
 通过自带的varnishlog指令可以获得varnish详细的系统运行日志。
例如:

  1. [root@varnish-server ~]#/usr/local/varnish/bin/varnishlog -n /data/varnish/cache
  2. 0 CLI          - Rd ping
  3. 0 CLI          - Wr 200 PONG 1279032175 1.0
  4. 0 CLI          - Rd ping
  5. 0 CLI          - Wr 200 PONG 1279032178 1.0

 通过自带的varnishncsa指令得到类似apache的combined输出格式的日志。
例如:

  1. [root@varnish-server ~]#/usr/local/varnish/bin/varnishncsa  -n  /data/varnish/cache

也可以将日志输出到一个文件中,通过“-w”参数指定即可:

  1. [root@varnish-server ~]#/usr/local/varnish/bin/varnishncsa -n /data/varnish/cache \
  2. >-w /data/varnish/log/varnish.log

varnish两种日志输出形式中,第一种在大多数情况下并不是必须的,这里重点介绍下第二种日志输出形式的配置方式。
下面编写一个名为varnishncsa的shell脚本,并把此文件放到/etc/init.d目录下,varnishncsa脚本的完整内容如下所示:

  1. #!/bin/sh
  2. if [ "$1" = "start" ];then
  3. /usr/local/varnish/bin/varnishncsa -n /data/varnish/cache  -f |/usr/sbin/rotatelogs /data/varnish/log/varnish.%Y.%m.%d.%H.log 3600 480 &
  4. elif [ "$1" = "stop" ];then
  5. killall varnishncsa
  6. else
  7. echo $0 "{start|stop}"
  8. fi

在这个脚本中,通过管道方式把日志导入到“rotatelogs”中,而rotatelogs是一个文件分割工具,它可以通过指定时间或者大小等方式来分割日志文件,这样就避免了日志文件过大造成的性能问题。
其中,“3600”是一个小时,也就是每个小时生成一个日志文件,“480”是一个时区参数,中国是第八时区,相对于UTC相差480分钟,如果不设置480这个参数,将导致日志记录时间和服务器时间相差8小时。关于rotatelogs命令用法,这里不再详细讲述。
通过对varnish日志的监控,可以知道varnish的运行状态和情况。
接着,将此脚本进行授权:

  1. [root@varnish-server ~]#chmod 755 /etc/init.d/varnishncsa

最后就可以通过如下方式,进行启动、关闭日志等操作了:

  1. [root@varnish-server ~]#/etc/init.d/varnishncsa  {start|stop }

四、管理Varnish

1、查看varnish进程
通过上面章节的讲解,varnish已经可以启动起来了,执行如下命令可以查看varnish是否正常启动:

  1. [root@varnish-server ~]# ps -ef|grep varnish
  2. root     29615     1  0 00:20 pts/1    00:00:00 /usr/local/varnish/bin/varnishncsa -n /data/varnish/cache -f
  3. root     29616     1  0 00:20 pts/1    00:00:00 /usr/sbin/rotatelogs /data/varnish/log/varnish.%Y.%m.%d.%H.log 3600 480
  4. root     29646     1  0 00:21 ?        00:00:00 /usr/local/varnish/sbin/varnishd -P /var/run/varnish.pid -a 192.168.12.246:80 -T 127.0.0.1:3500 -f /usr/local/varnish/etc/vcl.conf -u varnish -g varnish -w 2,51200,10 -n /data/varnish/cache -s file,/data/varnish/cache/varnish_cache.data,4G
  5. varnish  29647 29646  0 00:21 ?        00:00:00 /usr/local/varnish/sbin/varnishd -P /var/run/varnish.pid -a 192.168.12.246:80 -T 127.0.0.1:3500 -f /usr/local/varnish/etc/vcl.conf -u varnish -g varnish -w 2,51200,10 -n /data/varnish/cache -s file,/data/varnish/cache/varnish_cache.data,4G

从命令执行结果可知,PID为29615和29616的进程是varnish的日志输出进程,而PID为29646的进程是varnishd的主进程,并且派生出了一个PID为29647的子进程。这点跟apache类似。
如果varnish正常启动的话,80端口和3500端口应该处于监听状态,通过如下命令可以查看:

  1. [root@varnish-server ~]# netstat -antl|grep 3500
  2. tcp        0      0 127.0.0.1:3500              0.0.0.0:*                   LISTEN
  3. [root@varnish-server ~]#netstat -antl|grep 80
  4. tcp        0      0 192.168.12.246:80           0.0.0.0:*                   LISTEN
  5. tcp        1      0 192.168.12.246:41782        192.168.12.26:80            CLOSE_WAIT

其中,80端口为varnish的代理端口,3500为varnish的管理端口。
2、查看varnish缓存效果与状态
 可以通过浏览器访问对应的网页,查看varnish缓存的效果,如果varnish缓存成功的话,第二次打开网页的速度会明显比第一次快,但是这种方式并不能够完全说明问题,下面通过命令行方式,通过查看网页头来查看命中情况,操作如下:

  1. [root@varnish-server ~]# curl -I http://www.ixdba.net/a/mz/2010/0421/11.html
  2. HTTP/1.1 200 OK
  3. Server: Apache/2.2.14 (Unix) PHP/5.3.1 mod_perl/2.0.4 Perl/v5.10.1
  4. Last-Modified: Sat, 10 Jul 2010 11:25:15 GMT
  5. ETag: "5e850b-616d-48b06c6031cc0"
  6. Content-Type: text/html
  7. Content-Length: 24941
  8. Date: Fri, 09 Jul 2010 08:29:16 GMT
  9. X-Varnish: 1364285597
  10. Age: 0
  11. Via: 1.1 varnish
  12. Connection: keep-alive
  13. X-Cache: MISS from www.ixdba.net

#这里的"MISS"表示此次访问没有从缓存读取。
再次打开这个页面,查看网页头信息:

  1. [root@varnish-server ~]# curl -I http://www.ixdba.net/a/mz/2010/0421/11.html
  2. HTTP/1.1 200 OK
  3. Server: Apache/2.2.14 (Unix) PHP/5.3.1 mod_perl/2.0.4 Perl/v5.10.1
  4. Last-Modified: Sat, 10 Jul 2010 11:25:15 GMT
  5. ETag: "5e850b-616d-48b06c6031cc0"
  6. Content-Type: text/html
  7. Content-Length: 24941
  8. Date: Fri, 09 Jul 2010 08:30:35 GMT
  9. X-Varnish: 1364398612 1364285597
  10. Age: 79
  11. Via: 1.1 varnish
  12. Connection: keep-alive
  13. X-Cache: HIT from www.ixdba.net

#由“HIT”可知,第二次访问此页面时,是从缓存中读取内容了,也就是缓存命中。

缓存命中率的高低直接说明了varnish的运行状态和效果,较高的缓存命中率说明了varnish运行状态良好,web服务器的性能也会提高很多,反之,过低的缓存命中率说明varnish的配置可能存在问题,那么就需要进行调整,因此,从整体上了解varnish的命中率和缓存状态,对于优化和调整varnish至关重要。
varnish提供了一个varnishstat命令,通过它可以帮我们获得很多重要的信息。
下面是一个varnish系统的缓存状态:

  1. [root@varnish-server ~]#/usr/local/varnish/bin/varnishstat  -n /data/varnish/cache
  2. Hitrate ratio:       10      100      113
  3. Hitrate avg:     0.9999   0.9964   0.9964
  4. 9990        68.92        49.70 Client connections accepted
  5. 121820       953.84       606.07 Client requests received
  6. 112801       919.88       561.20 Cache hits
  7. 68         0.00         0.34 Cache misses
  8. 2688        33.96        13.37 Backend conn. success
  9. 6336         1.00        31.52 Backend conn. reuses
  10. 2642        33.96        13.14 Backend conn. was closed
  11. 8978        29.96        44.67 Backend conn. recycles
  12. 6389         1.00        31.79 Fetch with Length
  13. 2630        32.96        13.08 Fetch chunked
  14. 444          .            .   N struct sess_mem
  15. 23          .            .   N struct sess
  16. 64          .            .   N struct object
  17. 78          .            .   N struct objectcore
  18. 78          .            .   N struct objecthead
  19. 132          .            .   N struct smf
  20. 2          .            .   N small free smf
  21. 3          .            .   N large free smf
  22. 6          .            .   N struct vbe_conn
  23. 14          .            .   N worker threads
  24. 68         1.00         0.34 N worker threads created
  25. 0         0.00         0.00 N queued work requests
  26. 1201        11.99         5.98 N overflowed work requests
  27. 1          .            .   N backends
  28. 4          .            .   N expired objects
  29. 3701          .            .   N LRU moved objects
  30. 118109       942.85       587.61 Objects sent with write
  31. 9985        71.91        49.68 Total Sessions
  32. 121820       953.84       606.07 Total Requests

这里需要注意的几个地方是:
 “Client connections accepted”表示客户端向反向代理服务器成功发送HTTP请求的总数量。
 "Client requests received"表示到现在为止,浏览器向反向代理服务器发送HTTP请求的累积次数,由于可能会使用长连接,所以这个值一般会大于“Client connections accepted”。
 “Cache hits”表示反向代理服务器在缓存区中查找并且命中缓存的次数。
 “Cache misses”表示直接访问后端主机的请求数量,也就是非命中数。
 “N struct object”表示当前被缓存的数量。
 “N expired objects”表示过期的缓存内容数量。
 “N LRU moved objects”表示被淘汰的缓存内容个数。

五、管理varnish缓存内容
 Varnish的一个显著优点是可以灵活的管理缓存内容,而管理缓存主要的工作是如何迅速有效的控制和清除指定的缓存内容,varnish清除缓存相对比较复杂,不过幸运的是,可以通过varnish的管理端口发送PURGE指令来清除不需要的缓存。
下面列出了清除缓存内容的命令格式:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url  <regexp>
下面的命令可以列出最近清除的详细URL列表:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500  purge.list 
举例如下:
(1)如果要清除http://www.example.com/a/2010.html的URL地址,可以执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500  purge.url /a/2010.html
(2)批量清除类似http://www.example.com/a/b/s*.html的URL地址,可执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500  purge.url ^/a/b/s.*$
(3)批量清除类似http://www.example.com/a/b/*.html的URL地址,可执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500  purge.url  ^/a/b.*$
(4)如果要清除所有缓存,可执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url  ^.*$
(5)查看最近清除的详细URL列表
[root@varnish-server ~]# /usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.list
0x2dc310c0 1278674980.497631     0      req.url ~ /zm/a/web/2010/0423/64.html
0x2dc31100 1278674964.851327     1      req.url ~ ^/zm/a/d.*$
除了通过linux命令行方式清理varnish缓存外,还可以通过telnet到管理端口的方式来清理缓存页面,例如:

  1. [root@varnish-server ~]#telnet 192.168.12.246 3500
  2. Trying 192.168.12.246...
  3. Connected to localhost.localdomain (192.168.12.246).
  4. Escape character is '^]'.
  5. 200 154
  6. -----------------------------
  7. Varnish HTTP accelerator CLI.
  8. -----------------------------
  9. Type 'help' for command list.
  10. Type 'quit' to close CLI session.
  11. purge.url  /a/mz/2010/0421/11.html  #这里是清除这个页面缓存
  12. 200 0
  13. purge.url  ^/zm/a/d.*$   #这里是清除/zm/a/d/目录下所有以字母d开头的缓存页面
  14. 200 0

对于系统管理人员或者运维人员来说,时刻了解varnish命中率是至关重要的,虽然varnish给出了很详细的统计数据,但是统计的数据不是很直观,并且必须登录到varnish服务器才能查看,下面给出一个php程序,可以随时随地,并且非常清晰的了解varnish系统的命中率相关情况,程序如下:

  1. <?php
  2. // This is just a code snippet written by Jason "Foxdie" Gaunt, its not meant to be executed, it may work as-is, it may not.
  3. // I freely acknowledge this code is unoptimised but it has worked in practice for 6 months :)
  4. // Lets define our connection details
  5. $adminHost = "127.0.0.1"; // varnish服务器的IP地址
  6. $adminPort = "3500"; // varnish服务器管理端口
  7. // pollServer(str) - this function connects to the management port, sends the command and returns the results, or an error on failure
  8. function pollServer($command) {
  9. global $adminHost, $adminPort;
  10. $socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp"));
  11. if ((!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, Array("sec" => "5", "usec" => "0"))) OR (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, Array("sec" => "5", "usec" => "0"))))  {
  12. die("Unable to set socket timeout");
  13. }
  14. if (@socket_connect($socket, $adminHost, $adminPort)) {
  15. $data = "";
  16. if (!$socket) {
  17. die("Unable to open socket to " . $server . ":" . $port . "\n");
  18. }
  19. socket_write($socket, $command . "\n");
  20. socket_recv($socket, $buffer, 65536, 0);
  21. $data .= $buffer;
  22. socket_close($socket);
  23. return $data;
  24. }
  25. else {
  26. return "Unable to connect: " . socket_strerror(socket_last_error()) . "\n";
  27. }
  28. }
  29. // byteReduce(str) - this function converts a numeric value of bytes to a human readable format and returns the result
  30. function byteReduce($bytes) {
  31. // Terabytes
  32. if ($bytes > 1099511627776) {
  33. return round($bytes / 1099511627776) . "TB";
  34. }
  35. else if ($bytes > 1073741824) {
  36. return round($bytes / 1073741824) . "GB";
  37. }
  38. else if ($bytes > 1048576) {
  39. return round($bytes / 1048576) . "MB";
  40. }
  41. else if ($bytes > 1024) {
  42. return round($bytes / 1024) . "KB";
  43. }
  44. else {
  45. return $bytes . "B";
  46. }
  47. }
  48. // This is where our main code starts
  49. echo "<div class=\"inner\"><br />Statistics since last reset:<ul>";
  50. $stats = pollServer("stats");
  51. if (substr($stats, 0, 3) == "200") { // If request was legitimate
  52. // Clear all excessive white space and split by lines
  53. $stats = preg_replace("/ {2,}/", "|", $stats);
  54. $stats = preg_replace("/\n\|/", "\n", $stats);
  55. $statsArray = explode("\n", $stats);
  56. // Removes the first call return value and splits by pipe
  57. array_shift($statsArray);
  58. $statistics = array();
  59. foreach ($statsArray as $stat) {
  60. @$statVal = explode("|", $stat);
  61. @$statistics[$statVal[1]] = $statVal[0];
  62. }
  63. unset($stats, $statsArray, $stat, $statVal);
  64. // Start outputting statistics
  65. echo "<li>" . $statistics["Client connections accepted"] . " clients served over " . $statistics["Client requests received"] . " requests";
  66. echo "<li>" . round(($statistics["Cache hits"] / $statistics["Client requests received"]) * 100) . "% of requests served from cache";
  67. echo "<li>" . byteReduce($statistics["Total header bytes"] + $statistics["Total body bytes"]) . " served (" . byteReduce($statistics["Total header bytes"]) . " headers, " . byteReduce($statistics["Total body bytes"]) . " content)";
  68. // The following line is commented out because it only works when using file storage, I switched to malloc and this broke
  69. // echo "<li>" . byteReduce($statistics["bytes allocated"]) . " out of " . byteReduce($statistics["bytes allocated"] + $statistics["bytes free"]) . " used (" . round(($statistics["bytes allocated"] / ($statistics["bytes allocated"] + $statistics["bytes free"])) * 100) . "% usage)";
  70. }
  71. else {
  72. echo "Unable to get stats, error was: \"" . $stats;
  73. }
  74. echo "</ul></div>";
  75. ?>

将此php程序放到varnish服务器上,即可统计处当前varnish的命中率以及缓存状态,统计结果类似于下面的一个输出:

  1. Statistics since last reset:
  2.  63543 clients served over 584435 requests
  3.  98% of requests served from cache
  4.  4GB served (246MB headers, 4GB content)

在这个输出中,清晰的列出了浏览器请求总数、缓存命中率、缓存区中所有缓存内容的HTTP头信息长度和缓存内容的正文长度。根据这个结果判断,varnish的缓存效果还是很不错的,命中率很高。

高性能HTTP加速器Varnish(管理维护篇)相关推荐

  1. 高性能HTTP加速器Varnish(概念篇)

    一. Varnish概述  Varnish是一款高性能且开源的反向代理服务器和HTTP 加速器,它的作者Poul-Henning Kamp是FreeBSD核心的开发人员之一,Varnish采用全新的软 ...

  2. 高性能HTTP加速器Varnish(性能调优篇)

    varnish是否能稳定.快速的运行,与Linux本身的优化以及varnish自身参数的设置有很大关系,在varnish安装配置完成后,还必须从操作系统和varnish配置参数两个方面对varnish ...

  3. 高性能HTTP加速器Varnish(安装配置篇)

    一.安装Varnish Varnish的安装非常简单,下面逐步介绍: 1.安装前的准备  Varnish安装环境如下表1所示: 表1 主机名              操作系统             ...

  4. 高性能HTTP加速器varnish实践

    一,varnish介绍及特点 varnish是一款高性能的.轻量的.开源的反向代理服务器和HTTP加速器.Varnish代码量不大,先进的设计理念和成熟的设计框架是它的主要特征.目前在缓存工具的选择上 ...

  5. mysql数据库管理维护_深入浅出MySQL 数据库开发 优化与管理维护 第3版

    资料目录: 第 一部分 基础篇 第 1章 MySQL的安装与配置 2 1.1 MySQL的下载 2 1.1.1 在Windows平台下下载MySQL 3 1.1.2 在Linux平台下下载MySQL ...

  6. Varnish高性能开源HTTP加速器:Varnish Nginx和Varnish Apache搭建配置

    Varnish是一款高性能的开源HTTP加速器,一般用来和Nginx.Apache等搭配使用,组建一个高效率的Web服务器.Varnish的某个负责接受新HTTP连接的线程开始等待用户,如果有新的HT ...

  7. 读懂 JVM 内存管理这篇就够了

    读懂 JVM 内存管理这篇就够了 JVM 的内存结构 程序计数器 作用 概述 PC寄存器的常见问题 虚拟机栈 栈中可能出现的异常 栈的存储单位 栈运行原理 栈帧的内部结构 局部变量表 槽 Slot 操 ...

  8. Linux内存管理宏观篇(七)虚拟内存

    Linux内存管理宏观篇(七)虚拟内存 前面知道了物理内存,物理内存是实打实的,我只有这么多,用的时候你只能用这么多. 为了解决一些问题,产生虚拟内存,通过虚拟内存可以让我们每个进程都能拥有虚拟的3G ...

  9. 微指令地址的形成方式_交换那些事儿 | 基础维护篇 IPv6地址分类及配置方法

    IPv6地址分类及配置方法 H3C交换机基础维护篇 何为IPv6 随着网络的不断扩大和发展,IPv4的地址空间已不能满足需求,因此IPv6协议的应用越来越广泛.那么IPv6地址是如何规范和配置的呢,今 ...

最新文章

  1. 构建动态域名解析系统DDNS
  2. createDocumentFragment
  3. DHCP和DNS的概念—Vecloud微云
  4. 清华计算机知识工程怎么样,张民(muslv)清华大学计算机系知识工程组 硕士清华大学.ppt...
  5. Thinkphp5中异常处理不返回页面返回Json格式的字符串
  6. [Jarvis OJ - PWN]——Typo(内涵peak小知识)
  7. LINQ之路 2:C# 3.0的语言功能(上)
  8. php判断除数是不是整数,五种js判断是否为整数类型方式
  9. 二叉搜索树相关知识及应用操作
  10. 华为谷歌互利合作曝光:或将推Nexus手表
  11. python3多线程编程_Python 3多线程编程学习笔记-基础篇
  12. 最简单的视音频播放示例5:OpenGL播放RGB/YUV
  13. 【优化算法】蜜獾优化算法(HBA)【含Matlab源码 1437期】
  14. android9.0 从driver到APP(2)--hardware
  15. 开发rtmp直播流测试地址
  16. 软件耦合的分类及解决方法
  17. 原创 基于微信小程序毕业设计题目选题课题 自习室图书馆座位预约小程序的设计与实现(2)座位预约的实现
  18. 分蛋糕、思路视频(动态规划)
  19. BUUCTF之文件中的秘密
  20. 都说互联网很赚钱,真的?

热门文章

  1. python/正则 从字符串中提取数字
  2. 简历javaweb项目描述怎么写_硬件工程师简历-项目经验怎么写【范文】
  3. 解开Future的神秘面纱之任务执行
  4. 大约HR升级版的设计为组汇总
  5. 一个文件合成器的代码
  6. 计算SharePoint两个日期和时间字段之间的时间差值
  7. Windows命令行(DOS命令)教程
  8. [转] Tomcat 系统架构与设计模式,第 1 部分: 工作原理
  9. asterisk 常用命令
  10. jQuery 设置表格隔行变色、隔列变色