<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>jiangwenyuan (dreara)</title>
    <link>https://ruby-china.org/jiangwenyuan</link>
    <description>https://github.com/jiangwenyuan/nuster</description>
    <language>en-us</language>
    <item>
      <title>基于 HAProxy 的高性能 HTTP 缓存服务器和 RESTful NoSQL 缓存服务器</title>
      <description>&lt;h2 id="nuster"&gt;nuster&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/jiangwenyuan/nuster/wiki" rel="nofollow" target="_blank" title=""&gt;Wiki&lt;/a&gt; | &lt;a href="README.md" title=""&gt;English&lt;/a&gt; | &lt;a href="README-CN.md" title=""&gt;中文&lt;/a&gt; | &lt;a href="README-JP.md" title=""&gt;日本語&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;基于 HAProxy 的高性能 HTTP 缓存服务器和 RESTful NoSQL 缓存服务器。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;中文版更新可能不及时，最新版请参照英文版&lt;a href="README.md" title=""&gt;README.md&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E4%BB%8B%E7%BB%8D" title=""&gt;介绍&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E6%80%A7%E8%83%BD" title=""&gt;性能&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97" title=""&gt;入门指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95" title=""&gt;使用方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E6%8C%87%E4%BB%A4" title=""&gt;指令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="#cache" title=""&gt;Cache&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E7%BC%93%E5%AD%98%E7%AE%A1%E7%90%86" title=""&gt;管理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%BC%93%E5%AD%98%E5%BC%80%E5%90%AF%E5%85%B3%E9%97%AD" title=""&gt;开启关闭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%BC%93%E5%AD%98%E7%94%9F%E5%AD%98%E6%97%B6%E9%97%B4" title=""&gt;生存时间&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%BC%93%E5%AD%98%E6%B8%85%E9%99%A4" title=""&gt;清除&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%BC%93%E5%AD%98%E7%BB%9F%E8%AE%A1" title=""&gt;统计&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#nosql" title=""&gt;NoSQL&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#set" title=""&gt;Set&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#get" title=""&gt;Get&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#delete" title=""&gt;Delete&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%A1%AC%E7%9B%98%E6%8C%81%E4%B9%85%E5%8C%96" title=""&gt;硬盘持久化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#sample-fetches" title=""&gt;Sample fetches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#faq" title=""&gt;FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;nuster 是一个基于 HAProxy 的高性能 HTTP 缓存服务器和 RESTful NoSQL 缓存服务器，完全兼容 HAProxy，并且利用 HAProxy 的 ACL 功能来提供非常细致的缓存规则。&lt;/p&gt;
&lt;h2 id="特性"&gt;特性&lt;/h2&gt;&lt;h3 id="HTTP/TCP负载均衡器"&gt;HTTP/TCP负载均衡器&lt;/h3&gt;
&lt;p&gt;nuster 可以作为 HTTP/TCP 负载均衡器使用。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;继承了 HAProxy 的所有特性，完全兼容 HAProxy&lt;/li&gt;
&lt;li&gt;负载均衡&lt;/li&gt;
&lt;li&gt;前端后端 HTTPS&lt;/li&gt;
&lt;li&gt;HTTP 压缩&lt;/li&gt;
&lt;li&gt;HTTP 重写重定向&lt;/li&gt;
&lt;li&gt;HTTP 信息增删改&lt;/li&gt;
&lt;li&gt;HTTP2&lt;/li&gt;
&lt;li&gt;监控&lt;/li&gt;
&lt;li&gt;粘性&lt;/li&gt;
&lt;li&gt;访问控制&lt;/li&gt;
&lt;li&gt;内容切换&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="HTTP缓存服务器"&gt;HTTP 缓存服务器&lt;/h3&gt;
&lt;p&gt;nuster 也可以用作类似 Varnish 或者 Nginx 那样的 HTTP 缓存服务器，来缓存动态或者静态的 HTTP 资源。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HAProxy 的所有特性 (HTTPS, HTTP/2, ACL, etc)&lt;/li&gt;
&lt;li&gt;非常快&lt;/li&gt;
&lt;li&gt;强大的动态缓存功能

&lt;ul&gt;
&lt;li&gt;基于 HTTP method, URI, path, query, header, cookies, etc&lt;/li&gt;
&lt;li&gt;基于 HTTP request or response contents, etc&lt;/li&gt;
&lt;li&gt;基于 environment variables, server state, etc&lt;/li&gt;
&lt;li&gt;基于 SSL version, SNI, etc&lt;/li&gt;
&lt;li&gt;基于 connection rate, number, byte, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;缓存管理&lt;/li&gt;
&lt;li&gt;缓存清除&lt;/li&gt;
&lt;li&gt;缓存统计信息&lt;/li&gt;
&lt;li&gt;缓存生存时间&lt;/li&gt;
&lt;li&gt;持久化&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="RESTful NoSQL缓存服务器"&gt;RESTful NoSQL 缓存服务器&lt;/h3&gt;
&lt;p&gt;nuster 也可以用作 RESTful NoSQL 缓存服务器，用 HTTP &lt;code&gt;POST/GET/DELETE&lt;/code&gt; 来 添加/取得/删除 Key/Value.&lt;/p&gt;

&lt;p&gt;可以像 Memcached 或者 Redis 那样放在应用和数据库之间作为内部 KV 缓存使用，也可以放在用户和应用之间作为面向用户的 NoSQL 使用。
支持 header, cookie 等等，所以可以将不同的用户数据存到相同的路劲。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HAProxy 的所有特性 (HTTPS, HTTP/2, ACL, etc)&lt;/li&gt;
&lt;li&gt;有条件的缓存&lt;/li&gt;
&lt;li&gt;内部 KV 缓存&lt;/li&gt;
&lt;li&gt;面向用户缓存&lt;/li&gt;
&lt;li&gt;支持任何类型的数据&lt;/li&gt;
&lt;li&gt;支持所有编程语言，不需要特定的库，只需 HTTP 支持&lt;/li&gt;
&lt;li&gt;持久化&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="性能"&gt;性能&lt;/h2&gt;
&lt;p&gt;非常快，单进程模式下是 nginx 的 3 倍，多进程下 nginx 的 2 倍，varnish 的 3 倍。&lt;/p&gt;

&lt;p&gt;详见&lt;a href="https://github.com/jiangwenyuan/nuster/wiki/Performance-benchmark:-nuster-vs-nginx-vs-varnish" rel="nofollow" target="_blank" title=""&gt;benchmark&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="入门指南"&gt;入门指南&lt;/h2&gt;&lt;h2 id="下载"&gt;下载&lt;/h2&gt;
&lt;p&gt;生产环境的话从&lt;a href="Download.md" title=""&gt;Download&lt;/a&gt;下载最新稳定版，其他情况可以 git clone。&lt;/p&gt;
&lt;h2 id="编译"&gt;编译&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make TARGET=linux2628 USE_LUA=1 LUA_INC=/usr/include/lua5.3 USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1
make install PREFIX=/usr/local/nuster
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;添加&lt;code&gt;USE_PTHREAD_PSHARED=1&lt;/code&gt;使用 pthread&lt;/p&gt;

&lt;p&gt;如果不需要可以删除&lt;code&gt;USE_LUA=1 LUA_INC=/usr/include/lua5.3 USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;具体可以参考&lt;a href="README" title=""&gt;HAProxy README&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="配置文件"&gt;配置文件&lt;/h2&gt;
&lt;p&gt;准备一个配置文件：&lt;code&gt;nuster.cfg&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global
    nuster cache on data-size 100m uri /_nuster
    nuster nosql on data-size 200m
    master-worker # v3
defaults
    mode http
frontend fe
    bind *:8080
    #bind *:4433 ssl crt example.com.pem alpn h2,http/1.1
    use_backend be2 if { path_beg /_kv/ }
    default_backend be1
backend be1
    nuster cache on
    nuster rule img ttl 1d if { path_beg /img/ }
    nuster rule api ttl 30s if { path /api/some/api }
    server s1 127.0.0.1:8081
    server s2 127.0.0.1:8082
backend be2
    nuster nosql on
    nuster rule r1 ttl 3600
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;nuster 监听 8080 端口，接受 HTTP 请求。
&lt;code&gt;/_kv/&lt;/code&gt;开头的请求分配到 backend &lt;code&gt;be2&lt;/code&gt;, 可以发送 HTTP &lt;code&gt;POST/GET/DELETE&lt;/code&gt;到&lt;code&gt;/_kv/any_key&lt;/code&gt; 来 添加/取得/删除 Key/Value.
其他的请求都被分配到 backend &lt;code&gt;be1&lt;/code&gt;, 并且会被转发到服务器&lt;code&gt;s1&lt;/code&gt; or &lt;code&gt;s2&lt;/code&gt;. 其中&lt;code&gt;/img/*&lt;/code&gt;请求会被缓存 1 天，而&lt;code&gt;/api/some/api&lt;/code&gt;会被缓存 30 秒。&lt;/p&gt;
&lt;h2 id="启动"&gt;启动&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;/usr/local/nuster/sbin/nuster -f nuster.cfg&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="Docker"&gt;Docker&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull nuster/nuster
docker run -d -v /path/to/nuster.cfg:/etc/nuster/nuster.cfg:ro -p 8080:8080 nuster/nuster
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="使用方法"&gt;使用方法&lt;/h2&gt;
&lt;p&gt;nuster 基于 HAProxy, 支持所有的 HAProxy 指令。&lt;/p&gt;
&lt;h2 id="基本"&gt;基本&lt;/h2&gt;
&lt;p&gt;配置文件里有四个基本的&lt;code&gt;section&lt;/code&gt;s: &lt;code&gt;global&lt;/code&gt;, &lt;code&gt;defaults&lt;/code&gt;, &lt;code&gt;frontend&lt;/code&gt; and &lt;code&gt;backend&lt;/code&gt;。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;global

&lt;ul&gt;
&lt;li&gt;定义全局指令&lt;/li&gt;
&lt;li&gt;需要定义&lt;code&gt;nuster cache on&lt;/code&gt; or &lt;code&gt;nuster nosql on&lt;/code&gt;，否则 cache 和 nosql 无法使用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;defaults

&lt;ul&gt;
&lt;li&gt;定义&lt;code&gt;frontend&lt;/code&gt;, &lt;code&gt;backend&lt;/code&gt;的默认参数&lt;/li&gt;
&lt;li&gt;可以在&lt;code&gt;frontend&lt;/code&gt; or &lt;code&gt;backend&lt;/code&gt; section 重新定义&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;frontend

&lt;ul&gt;
&lt;li&gt;定义监听端口等等面向用户的设置&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;bankend

&lt;ul&gt;
&lt;li&gt;定义后端服务器等等设置&lt;/li&gt;
&lt;li&gt;需要设置&lt;code&gt;nuster cache on&lt;/code&gt; or &lt;code&gt;nuster nosql on&lt;/code&gt;, 否则该 backend 没有 nosql 或者 nosql 功能&lt;/li&gt;
&lt;li&gt;需要设置&lt;code&gt;nuster rule&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;可以定义多个&lt;code&gt;frontend&lt;/code&gt; or &lt;code&gt;backend&lt;/code&gt; . 如果定义了&lt;code&gt;nuster cache|nosql off&lt;/code&gt;或者没有&lt;code&gt;nuster cache|nosql on|off&lt;/code&gt;, nuster 就是一个 HAProxy。&lt;/p&gt;

&lt;p&gt;无法在&lt;code&gt;listen&lt;/code&gt;里定义 nuster。&lt;/p&gt;

&lt;p&gt;具体参考&lt;code&gt;/doc&lt;/code&gt;下的 HAProxy 文档，或者&lt;a href="https://cbonte.github.io/haproxy-dconv/" rel="nofollow" target="_blank" title=""&gt;在线 HAProxy 文档&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="As TCP loader balancer"&gt;As TCP loader balancer&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend mysql-lb
   bind *:3306
   mode tcp
   default_backend mysql-cluster
backend mysql-cluster
   balance roundrobin
   mode tcp
   server s1 10.0.0.101:3306
   server s2 10.0.0.102:3306
   server s3 10.0.0.103:3306
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="As HTTP/HTTPS loader balancer"&gt;As HTTP/HTTPS loader balancer&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend web-lb
   bind *:80
   #bind *:443 ssl crt XXX.pem
   mode http
   default_backend apps
backend apps
   balance roundrobin
   mode http
   server s1 10.0.0.101:8080
   server s2 10.0.0.102:8080
   server s3 10.0.0.103:8080
   #server s4 10.0.0.101:8443 ssl verify none
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="As HTTP cache server"&gt;As HTTP cache server&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global
    nuster cache on data-size 200m
frontend fe
    bind *:8080
    default_backend be
backend be
    nuster cache on
    nuster rule all
    server s1 127.0.0.1:8081
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="As RESTful NoSQL cache server"&gt;As RESTful NoSQL cache server&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global
    nuster nosql on data-size 200m
frontend fe
    bind *:8080
    default_backend be
backend be
    nuster nosql on
    nuster rule r1 ttl 3600
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="指令"&gt;指令&lt;/h2&gt;&lt;h2 id="global: nuster cache|nosql"&gt;global: nuster cache|nosql&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;syntax:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;nuster cache on|off [data-size size] [dict-size size] [dir DIR] [dict-cleaner n] [data-cleaner n] [disk-cleaner n] [disk-loader n] [disk-saver n] [purge-method method] [uri uri]&lt;/p&gt;

&lt;p&gt;nuster nosql on|off [data-size size] [dict-size size] [dir DIR] [dict-cleaner n] [data-cleaner n] [disk-cleaner n] [disk-loader n] [disk-saver n]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;default:&lt;/strong&gt; &lt;em&gt;none&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;context:&lt;/strong&gt; &lt;em&gt;global&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;控制是否开启 cache 或者 nosql。&lt;/p&gt;

&lt;p&gt;会分配一块&lt;code&gt;data-size + dict-size&lt;/code&gt;的共享内存来存储 HTTP 头，数据，key 等等，临时数据从系统内存池分配。
如果没有足够内存，新的请求不会被缓存直到有内存被释放。&lt;/p&gt;
&lt;h3 id="data-size"&gt;data-size&lt;/h3&gt;
&lt;p&gt;和&lt;code&gt;dict-size&lt;/code&gt;一起决定内存块的大小。&lt;/p&gt;

&lt;p&gt;可以使用&lt;code&gt;m&lt;/code&gt;, &lt;code&gt;M&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt; 和 &lt;code&gt;G&lt;/code&gt;.  默认是 1MB，同时也是最小值。&lt;/p&gt;
&lt;h3 id="dict-size"&gt;dict-size&lt;/h3&gt;
&lt;p&gt;决定 hash table 的大小。&lt;/p&gt;

&lt;p&gt;可以使用&lt;code&gt;m&lt;/code&gt;, &lt;code&gt;M&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt; 和 &lt;code&gt;G&lt;/code&gt;.  默认是 1MB，同时也是最小值。&lt;/p&gt;

&lt;p&gt;这个决定 hash table buckets 的大小，并非 key 的大小，key 存在共享内存中。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dict-size(bucket 数)&lt;/strong&gt; 不等于 &lt;strong&gt;key 数&lt;/strong&gt;. 就算 key 的数量超过了 dict-size，只要整个共享内存有空间，新的 key 仍然可以被添加。&lt;/p&gt;

&lt;p&gt;不过如果 key 数超过 dict-size(bucket 数) 性能也许会下降。dict-size 可以设为大概的最大 key 数乘以 8。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;将来版本会删除 dict-size, 像第一版本那样自动伸缩&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="dir"&gt;dir&lt;/h3&gt;
&lt;p&gt;设置硬盘缓存文件的根目录，必须设置以开启硬盘缓存功能。&lt;/p&gt;
&lt;h3 id="dict-cleaner"&gt;dict-cleaner&lt;/h3&gt;
&lt;p&gt;每次检查 &lt;code&gt;dict-cleaner&lt;/code&gt; 个 entry，无效的 entry 将被删除（默认 100）&lt;/p&gt;
&lt;h3 id="data-cleaner"&gt;data-cleaner&lt;/h3&gt;
&lt;p&gt;每次检查 &lt;code&gt;data-cleaner&lt;/code&gt; 个 entry，无效的 data 将被删除（默认 100）&lt;/p&gt;
&lt;h3 id="disk-cleaner"&gt;disk-cleaner&lt;/h3&gt;
&lt;p&gt;每次检查 &lt;code&gt;disk-cleaner&lt;/code&gt; 个硬盘缓存文件，无效的文件将被删除（默认 100）&lt;/p&gt;
&lt;h3 id="disk-loader"&gt;disk-loader&lt;/h3&gt;
&lt;p&gt;启动后每次加载 &lt;code&gt;disk-loader&lt;/code&gt; 个硬盘缓存文件的信息到内存（默认 100）&lt;/p&gt;
&lt;h3 id="disk-saver"&gt;disk-saver&lt;/h3&gt;
&lt;p&gt;每次检查 &lt;code&gt;disk-saver&lt;/code&gt; 个 data，并将需要保存至硬盘的 data 保存到硬盘（默认 100）&lt;/p&gt;

&lt;p&gt;详细请参考&lt;a href="#disk-mode" title=""&gt;nuster rule disk mode&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="purge-method [cache only]"&gt;purge-method [cache only]&lt;/h3&gt;
&lt;p&gt;自定义 PURGE 用的 HTTP method，最大 14 个字符，默认是 &lt;code&gt;PURGE&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="uri [cache only]"&gt;uri [cache only]&lt;/h3&gt;
&lt;p&gt;定义并开启 cache manager/stats API&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nuster cache on uri /_my/_unique/_/_cache/_uri&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;cache manager/stats默认是关闭的. 如果开启了，主义开启访问控制 (see &lt;a href="#how-to-restrict-access" title=""&gt;FAQ&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;具体请参考&lt;a href="#%E7%BC%93%E5%AD%98%E7%AE%A1%E7%90%86" title=""&gt;缓存管理&lt;/a&gt; 和 &lt;a href="#%E7%BC%93%E5%AD%98%E7%BB%9F%E8%AE%A1" title=""&gt;缓存统计&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="proxy: nuster cache|nosql"&gt;proxy: nuster cache|nosql&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;syntax:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;nuster cache [on|off]&lt;/p&gt;

&lt;p&gt;nuster nosql [on|off]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;default:&lt;/strong&gt; &lt;em&gt;on&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;context:&lt;/strong&gt; &lt;em&gt;backend&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;决定是否在这个 backend 开启 cache/nosql。
如果这个 section 有 filter，记得放在最后。&lt;/p&gt;
&lt;h2 id="nuster rule"&gt;nuster rule&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;syntax:&lt;/strong&gt; nuster rule name [key KEY] [ttl TTL] [code CODE] [disk MODE] [if|unless condition]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;default:&lt;/strong&gt; &lt;em&gt;none&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;context:&lt;/strong&gt; &lt;em&gt;backend&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;定义 cache/nosql 的生效条件，需要定义至少一个 rule。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuster cache on

# cache request `/asdf` for 30 seconds
nuster rule asdf ttl 30 if { path /asdf }

# cache if the request path begins with /img/
nuster rule img if { path_beg /img/ }

# cache if the response header `cache` is `yes`
acl resHdrCache res.hdr(cache) yes
nuster rule r1 if resHdrCache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以定义多个 rule，按定义顺序先后匹配。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;acl pathA path /a.html
nuster cache on
nuster rule all ttl 3600
nuster rule path01 ttl 60 if pathA
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rule &lt;code&gt;path01&lt;/code&gt;永远不会被匹配。&lt;/p&gt;
&lt;h3 id="name"&gt;name&lt;/h3&gt;
&lt;p&gt;定义 rule 的 name。&lt;/p&gt;

&lt;p&gt;在 cache manager API 中使用，不必唯一但是建议不同的 rule 用不同的 name，否则相同 name 的 rule 视作一样。&lt;/p&gt;
&lt;h3 id="key KEY"&gt;key KEY&lt;/h3&gt;
&lt;p&gt;定义 cache/nosql 的 key, 由下列关键字加&lt;code&gt;.&lt;/code&gt;组成&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;method:       http method, GET/POST...&lt;/li&gt;
&lt;li&gt;scheme:       http or https&lt;/li&gt;
&lt;li&gt;host:         the host in the request&lt;/li&gt;
&lt;li&gt;uri:          first slash to end of the url&lt;/li&gt;
&lt;li&gt;path:         the URL path of the request&lt;/li&gt;
&lt;li&gt;delimiter:    '?' if query exists otherwise empty&lt;/li&gt;
&lt;li&gt;query:        the whole query string of the request&lt;/li&gt;
&lt;li&gt;header_NAME: the value of header &lt;code&gt;NAME&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;cookie_NAME: the value of cookie &lt;code&gt;NAME&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;param_NAME:  the value of query &lt;code&gt;NAME&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;body:         the body of the request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CACHE 的默认 key 是 &lt;code&gt;method.scheme.host.uri&lt;/code&gt;, NoSQL 的默认 key 是 &lt;code&gt;GET.scheme.host.uri&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://www.example.com/q?name=X&amp;amp;type=Y

http header:
GET /q?name=X&amp;amp;type=Y HTTP/1.1
Host: www.example.com
ASDF: Z
Cookie: logged_in=yes; user=nuster;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;method:       GET&lt;/li&gt;
&lt;li&gt;scheme:       http&lt;/li&gt;
&lt;li&gt;host:         &lt;a href="http://www.example.com" rel="nofollow" target="_blank" title=""&gt;www.example.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;uri:          /q?name=X&amp;amp;type=Y&lt;/li&gt;
&lt;li&gt;path:         /q&lt;/li&gt;
&lt;li&gt;delimiter:    ?&lt;/li&gt;
&lt;li&gt;query:        name=X&amp;amp;type=Y&lt;/li&gt;
&lt;li&gt;header_ASDF: Z&lt;/li&gt;
&lt;li&gt;cookie_user: nuster&lt;/li&gt;
&lt;li&gt;param_type:  Y&lt;/li&gt;
&lt;li&gt;body:         (empty)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;默认 key 产生&lt;code&gt;GET\0http\0www.example.com\0/q?name=X&amp;amp;type=Y\0&lt;/code&gt;, 而&lt;code&gt;key method.scheme.host.path.header_ASDF.cookie_user.param_type&lt;/code&gt; 则生成 &lt;code&gt;GET\0http\0www.example.com\0/q\0Z\0nuster\0Y\0&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;\0&lt;/code&gt;是 NULL 字符&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;相同 key 的请求则会直接返回 cache 给客户端。&lt;/p&gt;
&lt;h3 id="ttl TTL"&gt;ttl TTL&lt;/h3&gt;
&lt;p&gt;设置缓存生存时间，过期后缓存会被删除。可以使用 &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;h&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;s&lt;/code&gt;。默认&lt;code&gt;0&lt;/code&gt;秒.
如果不希望失效则设为 0&lt;/p&gt;
&lt;h3 id="code CODE1,CODE2..."&gt;code CODE1,CODE2...&lt;/h3&gt;
&lt;p&gt;默认只缓存 200 的响应，如果需要缓存其他的则可以添加，&lt;code&gt;all&lt;/code&gt;会缓存任何状态码。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cache-rule only200
cache-rule 200and404 code 200,404
cache-rule all code all
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="disk MODE"&gt;disk MODE&lt;/h3&gt;
&lt;p&gt;定义缓存持久模式&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;off:   默认模式，仅保存在内存&lt;/li&gt;
&lt;li&gt;only:  不保存在内存，仅保存在硬盘&lt;/li&gt;
&lt;li&gt;sync:  保存到内存和硬盘后返回给客户端&lt;/li&gt;
&lt;li&gt;async: 保存到内存后立即换回给客户的，内存数据会由 master 进程在一定时间后保存至硬盘&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="if|unless condition"&gt;if|unless condition&lt;/h3&gt;
&lt;p&gt;定义 ACL 条件&lt;/p&gt;

&lt;p&gt;ACL 分别在请求阶段和响应阶段执行。&lt;/p&gt;

&lt;p&gt;当下述条件满足时，会进行缓存：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;在请求阶段 ACL 为真&lt;/li&gt;
&lt;li&gt;请求阶段 ACL 为假，但是响应阶段 ACL 为真&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;当使用否定的 ACL 或者某些样本获取方法时，需要特别注意&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;比如&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;缓存以&lt;code&gt;/img/&lt;/code&gt;开头的请求&lt;/p&gt;

&lt;p&gt;nuster rule img if { path_beg /img/ }&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;请求阶段要么为真要么为假，因为在响应阶段无法获取 path 所以永远为假。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;缓存响应的 http 头部&lt;code&gt;Content-Type&lt;/code&gt; 为 &lt;code&gt;image/jpeg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;nuster rule jpeg if { res.hdr(Content-Type) image/jpeg }&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;因为在请求阶段无法获取 res.hdr 所以永远为假，在响应阶段要么为真要么为假。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;以&lt;code&gt;/img/&lt;/code&gt;开头，并且响应头 &lt;code&gt;Content-Type&lt;/code&gt; 为&lt;code&gt;image/jpeg&lt;/code&gt;时缓存&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;如果定义为下面的规则，则不会成功：&lt;/p&gt;

&lt;p&gt;nuster rule img if { path_beg /img/ } { res.hdr(Content-Type) image/jpeg }&lt;/p&gt;

&lt;p&gt;因为在响应阶段无法获取 path 所以永远为假，而在请求阶段无法获取 res.hdr 所以永远为假，那么这个 ACL 就永远无法匹配。&lt;/p&gt;

&lt;p&gt;需要如下来定义：&lt;/p&gt;

&lt;p&gt;http-request set-var(txn.pathImg) path
    acl pathImg var(txn.pathImg) -m beg /img/
    acl resHdrCT res.hdr(Content-Type) image/jpeg
    nuster rule r3 if pathImg resHdrCT&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;另一个例子，缓存所有不以 &lt;code&gt;/api/&lt;/code&gt; 开头的请求&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;下面不正确：&lt;/p&gt;

&lt;p&gt;acl NoCache path_beg /api/
    nuster rule r3 if !NoCache&lt;/p&gt;

&lt;p&gt;因为虽然在响应阶段 path 并不存在，所以 NoCache 永远为假，而 &lt;code&gt;!NoCache&lt;/code&gt; 为真，所有的请求都会被缓存。&lt;/p&gt;

&lt;p&gt;需要改成：&lt;/p&gt;

&lt;p&gt;http-request set-var(txn.path) path
    acl NoCache var(txn.path) -m beg /api/
    nuster rule r1 if !NoCache&lt;/p&gt;

&lt;p&gt;会添加一些新的样本获取方法来简化这些操作。&lt;/p&gt;

&lt;p&gt;详见&lt;a href="doc/configuration.txt" title=""&gt;HAProxy configuration&lt;/a&gt;的&lt;strong&gt;7. Using ACLs and fetching samples&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="Cache"&gt;Cache&lt;/h2&gt;
&lt;p&gt;nuster 也可以用作类似 Varnish 或者 Nginx 那样的 HTTP 缓存服务器，来缓存动态或者静态的 HTTP 资源。
出了 HAProxy 的 SSL, HTTP, HTTP2, 重写重定向，增删改 Header 等等，还提供了下面的功能。&lt;/p&gt;
&lt;h2 id="缓存管理"&gt;缓存管理&lt;/h2&gt;
&lt;p&gt;缓存可以通过&lt;code&gt;uri&lt;/code&gt;定义一个 endpoint 并发送 HTTP 请求来进行管理。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;定义并且开启&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuster cache on uri /nuster/cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;基本用法&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -X POST -H "X: Y" http://127.0.0.1/nuster/cache&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;记得进行访问控制&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="缓存开启关闭"&gt;缓存开启关闭&lt;/h2&gt;
&lt;p&gt;rule 可以通过 manager uri 动态开启关闭，关闭的 rule 不会再进行匹配。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;header&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;state&lt;/td&gt;
&lt;td&gt;enable&lt;/td&gt;
&lt;td&gt;enable  rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;disable&lt;/td&gt;
&lt;td&gt;disable rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;rule NAME&lt;/td&gt;
&lt;td&gt;the rule to be enabled/disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;proxy NAME&lt;/td&gt;
&lt;td&gt;all rules belong to proxy NAME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;*&lt;/td&gt;
&lt;td&gt;all rules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;相同 name 的 rule 都会被开启关闭。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;关闭 rule r1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;curl -X POST -H "name: r1" -H "state: disable" http://127.0.0.1/nuster/cache&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;关闭 backend app1b 的所有 rule&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;curl -X POST -H "name: app1b" -H "state: disable" http://127.0.0.1/nuster/cache&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;开启所有的 rule&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;curl -X POST -H "name: *" -H "state: enable" http://127.0.0.1/nuster/cache&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="缓存生存时间"&gt;缓存生存时间&lt;/h2&gt;
&lt;p&gt;更改缓存 TTL，只会影响后续的新缓存，不会影响已经存在的缓存。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;header&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ttl&lt;/td&gt;
&lt;td&gt;new TTL&lt;/td&gt;
&lt;td&gt;see &lt;code&gt;ttl&lt;/code&gt; in &lt;code&gt;nuster rule&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;rule NAME&lt;/td&gt;
&lt;td&gt;the rule to be changed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;proxy NAME&lt;/td&gt;
&lt;td&gt;all rules belong to proxy NAME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;*&lt;/td&gt;
&lt;td&gt;all rules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST -H "name: r1" -H "ttl: 0" http://127.0.0.1/nuster/cache
curl -X POST -H "name: r2" -H "ttl: 2h" http://127.0.0.1/nuster/cache
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="同时设置state和ttl"&gt;同时设置 state 和 ttl&lt;/h2&gt;
&lt;p&gt;同时设置 state 和 ttl&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST -H "name: r1" -H "ttl: 0" -H "state: enabled" http://127.0.0.1/nuster/cache
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="缓存清除"&gt;缓存清除&lt;/h2&gt;
&lt;p&gt;There are several ways to purge cache by making HTTP &lt;code&gt;PURGE&lt;/code&gt; requests to the manager uri defined by &lt;code&gt;uri&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can define customized http method using &lt;code&gt;purge-method MYPURGE&lt;/code&gt; other than the default &lt;code&gt;PURGE&lt;/code&gt; in case you need to forward &lt;code&gt;PURGE&lt;/code&gt; to backend servers.&lt;/p&gt;
&lt;h3 id="删除一个特定URL"&gt;删除一个特定 URL&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl -XPURGE https://127.0.0.1/imgs/test.jpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;生成 key &lt;code&gt;GET.scheme.host.uri&lt;/code&gt;, 并删除那个 key。&lt;/p&gt;

&lt;p&gt;默认 key 包含&lt;code&gt;Host&lt;/code&gt;, 如果缓存时用了&lt;code&gt;http://example.com/test&lt;/code&gt; 而在 localhost 删除是需要&lt;code&gt;Host&lt;/code&gt; header:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -XPURGE -H "Host: example.com" http://127.0.0.1/test&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="通过name删除"&gt;通过 name 删除&lt;/h3&gt;
&lt;p&gt;可以通过带上&lt;code&gt;name&lt;/code&gt; header 来 &lt;code&gt;PURGE&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;header&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;nuster rule NAME&lt;/td&gt;
&lt;td&gt;caches belong to rule ${NAME} will be purged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;proxy NAME&lt;/td&gt;
&lt;td&gt;caches belong to proxy ${NAME}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;*&lt;/td&gt;
&lt;td&gt;all caches&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 删除所有缓存
curl -X PURGE -H "name: *" http://127.0.0.1/nuster/cache
# 删除backend applb的所有缓存
curl -X PURGE -H "name: app1b" http://127.0.0.1/nuster/cache
# 删除所有rule r1生成的缓存
curl -X PURGE -H "name: r1" http://127.0.0.1/nuster/cache
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="通过host删除"&gt;通过 host 删除&lt;/h3&gt;
&lt;p&gt;通过带上&lt;code&gt;x-host&lt;/code&gt;header 来删除所有属于这个 host 的缓存。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;header&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x-host&lt;/td&gt;
&lt;td&gt;HOST&lt;/td&gt;
&lt;td&gt;the ${HOST}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X PURGE -H "x-host: 127.0.0.1:8080" http://127.0.0.1/nuster/cache
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="通过path删除"&gt;通过 path 删除&lt;/h3&gt;
&lt;p&gt;默认情况下，query 部分也包含在 key 中，所以相同的 path 不同的 query 会产生不同的缓存。&lt;/p&gt;

&lt;p&gt;比如&lt;code&gt;nuster rule imgs if { path_beg /imgs/ }&lt;/code&gt;, 然后请求&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://127.0.0.1/imgs/test.jpg?w=120&amp;amp;h=120
curl https://127.0.0.1/imgs/test.jpg?w=180&amp;amp;h=180
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会生成两个缓存，因为 query 不一样。&lt;/p&gt;

&lt;p&gt;如果要删除这些缓存，可以&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;如果知道所有的 query，那么可以一个一个删除&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -XPURGE https://127.0.0.1/imgs/test.jpg?w=120&amp;amp;h=120
curl -XPURGE https://127.0.0.1/imgs/test.jpg?w=180&amp;amp;h=180
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;大多数情况下不知道所有的 query&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;如果 query 部分不重要，则可以从 key 里面删除 query&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;定义&lt;code&gt;nuster rule imgs key method.scheme.host.path if { path_beg /imgs }&lt;/code&gt;, 这样的话只会生成一个缓存，那么就可以不用 query 删除缓存&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -XPURGE https://127.0.0.1/imgs/test.jpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;大多数情况需要 query&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;通过 rule name 删除&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -X PURGE -H "name: imgs" http://127.0.0.1/nuster/cache&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;但是如果 rule 被定义成了 &lt;code&gt;nuster rule static if { path_beg /imgs/ /css/ }&lt;/code&gt;，则无法只删除 imgs&lt;/p&gt;

&lt;p&gt;因此，可以通过 path 删除&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;header&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;path&lt;/td&gt;
&lt;td&gt;PATH&lt;/td&gt;
&lt;td&gt;caches with ${PATH} will be purged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x-host&lt;/td&gt;
&lt;td&gt;HOST&lt;/td&gt;
&lt;td&gt;and host is ${HOST}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 删除所有path是/imgs/test.jpg的缓存
curl -X PURGE -H "path: /imgs/test.jpg" http://127.0.0.1/nuster/cache
# 删除所有path是/imgs/test.jpg 并且host是127.0.0.1:8080的缓存
curl -X PURGE -H "path: /imgs/test.jpg" -H "x-host: 127.0.0.1:8080" http://127.0.0.1/nuster/cache
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="通过正则删除"&gt;通过正则删除&lt;/h3&gt;
&lt;p&gt;也可以通过正则删除，所有匹配正则的缓存将被删除。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;header&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;regex&lt;/td&gt;
&lt;td&gt;REGEX&lt;/td&gt;
&lt;td&gt;caches which path match with ${REGEX} will be purged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x-host&lt;/td&gt;
&lt;td&gt;HOST&lt;/td&gt;
&lt;td&gt;and host is ${HOST}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 删除所有 /imgs 开头 .jpg结尾的缓存
curl -X PURGE -H "regex: ^/imgs/.*\.jpg$" http://127.0.0.1/nuster/cache
#delete all caches which path starts with /imgs and ends with .jpg and belongs to 127.0.0.1:8080
curl -X PURGE -H "regex: ^/imgs/.*\.jpg$" -H "127.0.0.1:8080" http://127.0.0.1/nuster/cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;PURGE 注意事项&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;开启访问控制&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果有多个 header，按照&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;path &amp;amp; host&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;regex &amp;amp; host&lt;/code&gt;, &lt;code&gt;regex&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;的顺序处理&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;curl -XPURGE -H "name: rule1" -H "path: /imgs/a.jpg"&lt;/code&gt;: purge by name&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;如果有重复的 header，处理第一个&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;curl -XPURGE -H "name: rule1" -H "name: rule2"&lt;/code&gt;: purge by &lt;code&gt;rule1&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;regex&lt;/code&gt; &lt;strong&gt;不是 glob&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;比如 /imgs 下的.jpg 文件是&lt;code&gt;^/imgs/.*\.jpg$&lt;/code&gt; 而不是 &lt;code&gt;/imgs/*.jpg&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;通过 rule name 或 proxy name 删除缓存时，需要注意这两种方法只在当前进程有效。如果重启了进程则无法通过这两种方法删除缓存文件，因为 rule name 信息和 proxy name 信息并没有保存在缓存文件中。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;只有 disk load 结束后才能通过 host or path or regex 来删除缓存文件。是否已经 load 结束可以查看 stats URL。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="缓存统计"&gt;缓存统计&lt;/h2&gt;
&lt;p&gt;可以通过 GET &lt;code&gt;uri&lt;/code&gt;定义的 endpoint 来获取缓存统计信息。&lt;/p&gt;
&lt;h3 id="Eanble and define the endpoint"&gt;Eanble and define the endpoint&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuster cache on uri /nuster/cache
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Usage"&gt;Usage&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl http://127.0.0.1/nuster/cache&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="Output"&gt;Output&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;used_mem:  http 缓存使用的内存，不包括 overhead&lt;/li&gt;
&lt;li&gt;req_total: 开启了 cache 的所有的 backend 的总请求数，不包含那些没有 cache 的 backend 的请求数&lt;/li&gt;
&lt;li&gt;req_hit:   cache 击中数&lt;/li&gt;
&lt;li&gt;req_fetch: 从后端取得数量&lt;/li&gt;
&lt;li&gt;req_abort: 中断的请求&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="NoSQL"&gt;NoSQL&lt;/h2&gt;
&lt;p&gt;nuster 也可以用作 RESTful NoSQL 缓存服务器，用 HTTP &lt;code&gt;POST/GET/DELETE&lt;/code&gt; 来 添加/取得/删除 Key/Value.&lt;/p&gt;
&lt;h2 id="基本操作"&gt;基本操作&lt;/h2&gt;&lt;h3 id="Set"&gt;Set&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v -X POST -d value1 http://127.0.0.1:8080/key1
curl -v -X POST --data-binary @icon.jpg http://127.0.0.1:8080/imgs/icon.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Get"&gt;Get&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl -v http://127.0.0.1:8080/key1&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="Delete"&gt;Delete&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl -v -X DELETE http://127.0.0.1:8080/key1&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="Response"&gt;Response&lt;/h2&gt;
&lt;p&gt;Check status code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;200 OK

&lt;ul&gt;
&lt;li&gt;POST/GET: 成功&lt;/li&gt;
&lt;li&gt;DELETE: 总是&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;400 Bad request

&lt;ul&gt;
&lt;li&gt;空值&lt;/li&gt;
&lt;li&gt;不正确的 acl, rules, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;404 Not Found

&lt;ul&gt;
&lt;li&gt;POST: rule tests 失败&lt;/li&gt;
&lt;li&gt;GET: not found&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;405 Method Not Allowed

&lt;ul&gt;
&lt;li&gt;其他的 methods&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;500 Internal Server Error

&lt;ul&gt;
&lt;li&gt;发生未知错误&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;507 Insufficient Storage

&lt;ul&gt;
&lt;li&gt;超过 data-size&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="分用户的data"&gt;分用户的 data&lt;/h2&gt;
&lt;p&gt;通过在 key 里加入 header, cookie 等等，可以将不同的用户数据存到相同的路劲。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nuster rule r1 key method.scheme.host.uri.header_userId if { path /mypoint }
nuster rule r2 key method.scheme.host.uri.cookie_sessionId if { path /mydata }
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Set"&gt;Set&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v -X POST -d "333" -H "userId: 1000" http://127.0.0.1:8080/mypoint
curl -v -X POST -d "555" -H "userId: 1001" http://127.0.0.1:8080/mypoint

curl -v -X POST -d "userA data" --cookie "sessionId=ijsf023xe" http://127.0.0.1:8080/mydata
curl -v -X POST -d "userB data" --cookie "sessionId=rosre329x" http://127.0.0.1:8080/mydata
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Get"&gt;Get&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v http://127.0.0.1:8080/mypoint
&amp;lt; 404 Not Found

curl -v -H "userId: 1000" http://127.0.0.1:8080/mypoint
&amp;lt; 200 OK
333

curl -v --cookie "sessionId=ijsf023xe" http://127.0.0.1:8080/mydata
&amp;lt; 200 OK
userA data
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="客户端"&gt;客户端&lt;/h2&gt;
&lt;p&gt;支持任何支持 HTTP 的客户端，库：&lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;postman&lt;/code&gt;, python &lt;code&gt;requests&lt;/code&gt;, go &lt;code&gt;net/http&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h2 id="硬盘持久化"&gt;硬盘持久化&lt;/h2&gt;
&lt;p&gt;配置文件&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global
    master-worker
    nuster cache on data-size 10m dir /tmp/cache
    nuster nosql on data-size 10m dir /tmp/nosql
backend be
    nuster cache on
    nuster rule off   disk off   ttl 1m if { path_beg /disk-off }
    nuster rule only  disk only  ttl 1d if { path_beg /disk-only }
    nuster rule sync  disk sync  ttl 1h if { path_beg /disk-sync }
    nuster rule async disk async ttl 2h if { path_beg /disk-async }
    nuster rule others ttl 100
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;/disk-off&lt;/code&gt; 仅保存在内存&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/disk-only&lt;/code&gt; 仅保存在硬盘&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/disk-sync&lt;/code&gt; 保存至内存和硬盘后返回给客户端&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/disk-async&lt;/code&gt; 保存至内存后立即换回给客户端，内存数据会在一定时间后被缓存至硬盘&lt;/li&gt;
&lt;li&gt;其他的所有请求都仅保存在内存&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="Sample fetches"&gt;Sample fetches&lt;/h2&gt;
&lt;p&gt;Nuster 加入了一些新的 sample fetches&lt;/p&gt;
&lt;h2 id="nuster.cache.hit: boolean"&gt;nuster.cache.hit: boolean&lt;/h2&gt;
&lt;p&gt;表示是否是 HIT 缓存，可以像如下使用&lt;/p&gt;

&lt;p&gt;http-response set-header x-cache hit if { nuster.cache.hit }&lt;/p&gt;
&lt;h2 id="FAQ"&gt;FAQ&lt;/h2&gt;&lt;h2 id="无法启动，报错: not in master-worker mode"&gt;无法启动，报错：not in master-worker mode&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;global&lt;/code&gt; 添加 &lt;code&gt;master-worker&lt;/code&gt; 或者启动时使用&lt;code&gt;-W&lt;/code&gt;参数。&lt;/p&gt;
&lt;h2 id="如何调试?"&gt;如何调试？&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;global&lt;/code&gt;添加&lt;code&gt;debug&lt;/code&gt;，或者带&lt;code&gt;-d&lt;/code&gt;启动&lt;code&gt;nuster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;nuster 相关的调试信息以&lt;code&gt;[nuster&lt;/code&gt;开头&lt;/p&gt;
&lt;h2 id="如何缓存POST请求?"&gt;如何缓存 POST 请求？&lt;/h2&gt;
&lt;p&gt;添加&lt;code&gt;option http-buffer-request&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;如果自定义了 key 的话需要使用&lt;code&gt;body&lt;/code&gt;关键字&lt;/p&gt;

&lt;p&gt;请求 body 可能不完整，详见&lt;a href="doc/configuration.txt" title=""&gt;HAProxy configuration&lt;/a&gt; 的 &lt;strong&gt;option http-buffer-request&lt;/strong&gt;小节&lt;/p&gt;

&lt;p&gt;另外可以为 post 请求单独设置一个后端&lt;/p&gt;
&lt;h2 id="如何做访问控制?"&gt;如何做访问控制？&lt;/h2&gt;
&lt;p&gt;类似&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;acl network_allowed src 127.0.0.1
acl purge_method method PURGE
http-request deny if purge_method !network_allowed
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="如何开启HTTP2?"&gt;如何开启 HTTP2?&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind :443 ssl crt pub.pem alpn h2,http/1.1
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Example"&gt;Example&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global
    nuster cache on data-size 100m
    nuster nosql on data-size 100m
    master-worker # v3
    # daemon
    # debug
defaults
    retries 3
    option redispatch
    timeout client  30s
    timeout connect 30s
    timeout server  30s
frontend web1
    bind *:8080
    mode http
    acl pathPost path /search
    use_backend app1a if pathPost
    default_backend app1b
backend app1a
    balance roundrobin
    # mode must be http
    mode http

    # http-buffer-request must be enabled to cache post request
    option http-buffer-request

    acl pathPost path /search

    # enable cache for this proxy
    nuster cache

    # cache /search for 120 seconds. Only works when POST/PUT
    nuster rule rpost key method.scheme.host.uri.body ttl 120 if pathPost

    server s1 10.0.0.10:8080
backend app1b
    balance     roundrobin
    mode http

    nuster cache on

    # cache /a.jpg, not expire
    acl pathA path /a.jpg
    nuster rule r1 ttl 0 if pathA

    # cache /mypage, key contains cookie[userId], so it will be cached per user
    acl pathB path /mypage
    nuster rule r2 key method.scheme.host.path.delimiter.query.cookie_userId ttl 60 if pathB

    # cache /a.html if response's header[cache] is yes
    http-request set-var(txn.pathC) path
    acl pathC var(txn.pathC) -m str /a.html
    acl resHdrCache1 res.hdr(cache) yes
    nuster rule r3 if pathC resHdrCache1

    # cache /heavy for 100 seconds if be_conn greater than 10
    acl heavypage path /heavy
    acl tooFast be_conn ge 100
    nuster rule heavy ttl 100 if heavypage tooFast

    # cache all if response's header[asdf] is fdsa
    acl resHdrCache2 res.hdr(asdf)  fdsa
    nuster rule resCache ttl 0 if resHdrCache1

    server s1 10.0.0.10:8080

frontend web2
    bind *:8081
    mode http
    default_backend app2
backend app2
    balance     roundrobin
    mode http

    # disable cache on this proxy
    nuster cache off
    nuster rule all

    server s2 10.0.0.11:8080

frontend nosql_fe
    bind *:9090
    default_backend nosql_be
backend nosql_be
    nuster nosql on
    nuster rule r1 ttl 3600
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Contributing"&gt;Contributing&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Join the development&lt;/li&gt;
&lt;li&gt;Give feedback&lt;/li&gt;
&lt;li&gt;Report issues&lt;/li&gt;
&lt;li&gt;Send pull requests&lt;/li&gt;
&lt;li&gt;Spread nuster&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="License"&gt;License&lt;/h2&gt;
&lt;p&gt;Copyright (C) 2017-2018, &lt;a href="https://github.com/jiangwenyuan" rel="nofollow" target="_blank" title=""&gt;Jiang Wenyuan&lt;/a&gt;, &amp;lt; koubunen AT gmail DOT com &amp;gt;&lt;/p&gt;

&lt;p&gt;All rights reserved.&lt;/p&gt;

&lt;p&gt;Licensed under GPL, the same as HAProxy&lt;/p&gt;

&lt;p&gt;HAProxy and other sources license notices: see relevant individual files.&lt;/p&gt;</description>
      <author>jiangwenyuan</author>
      <pubDate>Mon, 09 Jul 2018 08:55:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/37121</link>
      <guid>https://ruby-china.org/topics/37121</guid>
    </item>
    <item>
      <title>开源高性能 Web 缓存服务器 nuster</title>
      <description>&lt;p&gt;nuster, 一个基于 HAProxy 的高性能 web 缓存服务器。完全兼容 HAProxy，并且利用 HAProxy 的 ACL 功能来提供非常细致的缓存规则。&lt;/p&gt;

&lt;p&gt;项目地址 &lt;a href="https://github.com/jiangwenyuan/nuster" rel="nofollow" target="_blank"&gt;https://github.com/jiangwenyuan/nuster&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;可以根据 url, path, query, header, cookie，请求速率等等来动态生成缓存，并设置有效期。支持 purge，支持前后端 HTTPS。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   完全兼容 HAProxy，支持所有 HAProxy 的特性和功能&lt;/li&gt;
&lt;li&gt;   强大的动态缓存功能

&lt;ul&gt;
&lt;li&gt;     根据 HTTP method, uri, path, query, header, cookie 等等进行缓存&lt;/li&gt;
&lt;li&gt;     根据 HTTP 请求和响应内容等等进行缓存&lt;/li&gt;
&lt;li&gt;     根据环境变量服务器状态等等进行缓存&lt;/li&gt;
&lt;li&gt;     根据 SSL 版本，SNI 等等进行缓存&lt;/li&gt;
&lt;li&gt;     根据连接数量，请求速率等等进行缓存&lt;/li&gt;
&lt;li&gt;     等等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;   非常快&lt;/li&gt;
&lt;li&gt;   删除缓存&lt;/li&gt;
&lt;li&gt;   前后端 HTTPS&lt;/li&gt;
&lt;li&gt;   HTTP 压缩&lt;/li&gt;
&lt;li&gt;   HTTP 重写重定向&lt;/li&gt;
&lt;li&gt;   等等&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;性能&lt;/p&gt;

&lt;p&gt;非常快，单进程模式下是 nginx 的 3 倍，多进程下 nginx 的 2 倍，varnish 的 3 倍。&lt;/p&gt;

&lt;p&gt;详见&lt;a href="https://github.com/jiangwenyuan/nuster/wiki/Web-cache-server-performance-benchmark:-nuster-vs-nginx-vs-varnish-vs-squid" rel="nofollow" target="_blank" title=""&gt;https://github.com/jiangwenyuan/nuster/wiki/Web-cache-server-performance-benchmark:-nuster-vs-nginx-vs-varnish-vs-squid&lt;/a&gt;&lt;/p&gt;</description>
      <author>jiangwenyuan</author>
      <pubDate>Thu, 22 Feb 2018 10:59:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/35055</link>
      <guid>https://ruby-china.org/topics/35055</guid>
    </item>
  </channel>
</rss>
