月度归档:2013年01月

常见MySQL error code和SQLSTATE code

常见MySQL error code和SQLSTATE code:

MySQL error code        SQLSTATE code            Error message

1011                    HY000                    Error on delete of '%s' (errno: %d)

1021                    HY000                    Disk full (%s); waiting for someone to free some space...

1022                    23000                    Can't write; duplicate key in table '%s'

1027                    HY000                    '%s' is locked against change

1036                    HY000                    Table '%s' is read only

1048                    23000                    Column '%s' cannot be null

1062                    23000                    Duplicate entry '%s' for key %d

1099                    HY000                    Table '%s' was locked with a READ lock and can't be updated

1100                    HY000                    Table '%s' was not locked with LOCK TABLES

1104                    42000                    The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay

1106                    42000                    Incorrect parameters to procedure '%s'

1114                    HY000                    The table '%s' is full

1150                    HY000                    Delayed insert thread couldn't get requested lock for table %s

1165                    HY000                    INSERT DELAYED can't be used with table '%s' because it is locked with LOCK TABLES

1242                    21000                    Subquery returns more than 1 row

1263                    22004                    Column set to default value; NULL supplied to NOT NULL column '%s' at row %ld

1264                    22003                    Out of range value adjusted for column '%s' at row %ld

1265                    1000                     Data truncated for column '%s' at row %ld

1312                    0A000                    SELECT in a stored program must have INTO

1317                    70100                    Query execution was interrupted

1319                    42000                    Undefined CONDITION: %s

1325                    24000                    Cursor is already open

1326                    24000                    Cursor is not open

1328                    HY000                    Incorrect number of FETCH variables

1329                    2000                     No data to FETCH

1336                    42000                    USE is not allowed in a stored program

1337                    42000                    Variable or condition declaration after cursor or handler declaration

1338                    42000                    Cursor declaration after handler declaration

1339                    20000                    Case not found for CASE statement

1348                    HY000                    Column '%s' is not updatable

1357                    HY000                    Can't drop a %s from within another stored routine

1358                    HY000                    GOTO is not allowed in a stored program handler

1362                    HY000                    Updating of %s row is not allowed in %s trigger

1363                    HY000                    There is no %s row in %s trigger

mysql DECLARE

DECLARE condition_name CONDITION FOR condition_value
 
condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | mysql_error_code

这个语句指定需要特殊处理的条件。它将一个名字和指定的错误条件关联起来。这个名字可以随后被用在DECLARE HANDLER语句中。请参阅20.2.10.2节,“DECLARE处理程序

除了SQLSTATE值,也支持MySQL错误代码。

20.2.10.2. DECLARE处理程序

DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement
 
handler_type:
    CONTINUE
  | EXIT
  | UNDO
 
condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | condition_name
  | SQLWARNING
  | NOT FOUND
  | SQLEXCEPTION
  | mysql_error_code

这个语句指定每个可以处理一个或多个条件的处理程序。如果产生一个或多个条件,指定的语句被执行。

对一个CONTINUE处理程序,当前子程序的执行在执行 处理程序语句之后继续。对于EXIT处理程序,当前BEGIN...END复合语句的执行被终止。UNDO 处理程序类型语句还不被支持。

·         SQLWARNING是对所有以01开头的SQLSTATE代码的速记。

·         NOT FOUND是对所有以02开头的SQLSTATE代码的速记。

·         SQLEXCEPTION是对所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE代码的速记。

除了SQLSTATE值,MySQL错误代码也不被支持。

例如:

mysql> CREATE TABLE test.t (s1 int,primary key (s1));
Query OK, 0 rows affected (0.00 sec)
 
mysql> delimiter //
 
mysql> CREATE PROCEDURE handlerdemo ()
    -> BEGIN
    ->   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
    ->   SET @x = 1;
    ->   INSERT INTO test.t VALUES (1);
    ->   SET @x = 2;
    ->   INSERT INTO test.t VALUES (1);
    ->   SET @x = 3;
    -> END;
    -> //
Query OK, 0 rows affected (0.00 sec)
 
mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT @x//
    +------+
    | @x   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)

注意到,@x是3,这表明MySQL被执行到程序的末尾。如果DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; 这一行不在,第二个INSERT因PRIMARY KEY强制而失败之后,MySQL可能已经采取 默认(EXIT)路径,并且SELECT @x可能已经返回2。

mysql 自增ID

Q:怎么获得当前的自增的最大值? 
A:select @@identity

Q:怎么获得table的当前自增最大值? 
A:select max(id) from table

Q:MYSQL中的LAST_INSERT_ID()和MSSQL中的@@IDENTITY 
A:按照应用需要,常常要取得刚刚插入数据库表里的记录的ID值。 
   在MYSQL中可以使用LAST_INSERT_ID()函数,在MSSQL中使用@@IDENTITY。挺方便的一个函数。

  但是,这里需要注意的是,当使用INSERT语句插入多条记录的时候,使用LAST_INSERT_ID()返回的还是第一条的   ID值,而@@IDENTITY返回最后一条。

 

SELECT LAST_INSERT_ID()  线程安全

iis7+ rewrite variable

"CACHE_URL",
"DOCUMENT_ROOT",
"HTTP_URL",
"HTTP_HOST",
"PATH_INFO",
"PATH_TRANSLATED",
"QUERY_STRING",
"REQUEST_FILENAME",
"REQUEST_URI",
"SCRIPT_FILENAME",
"SCRIPT_NAME",
"SCRIPT_TRANSLATED",
"UNENCODED_URL",
"URL",
"URL_PATH_INFO",
"APP_POOL_ID",
"APPL_MD_PATH",
"APPL_PHYSICAL_PATH",
"GATEWAY_INTERFACE",
"SERVER_SOFTWARE",
"SSI_EXEC_DISABLED"

 

link: http://www.iis.net/learn/extensions/url-rewrite-module/url-rewrite-module-configuration-reference

varnish 参数说明

vcl_init

Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.

当VCL加载时调用,之后加载客户请求。一般用于初始化VMOD模块。

return() values:

返回值有:

ok Normal return, VCL continues loading.

OK 正常返回值,返回OK后VCL加载。

vcl_recv

Called at the beginning of a request, after the complete request has been received and parsed. 

Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, 

which backend to use.

在请求完全接收并解析完之后,从请求的开始处调用,他的目的是决定是否处理请求,怎么处理请求,或者如果后端有多个服务器的话,决定去调用哪个。

The vcl_recv subroutine may terminate with calling return() on one of the following keywords:

vcl_recv子程序可以通过调用以下关键字通过return()来终止处理:

error code [reason]Return the specified error code to the client and abandon the request.

error code [reason]  给客户端返回指定的错误代码并丢弃请求。

pass  Switch to pass mode. Control will eventually pass to vcl_pass.

pass  传送到pass模式,控制权将最终交给vcl_pass.

pipe   Switch to pipe mode. Control will eventually pass to vcl_pipe.

pipe  传送到pipe模式,控制权将最终交给vcl_pipe.

lookup   Look up the requested object in the cache. Control will eventually pass to vcl_hit or vcl_miss, 

depending on whether the object is in the cache.

lookup  从缓存中查找对象,控制权将最终交给vcl_hit或者vcl_miss,这取决于是否从缓存中命中对象。

vcl_pipe

Called upon entering pipe mode. In this mode, the request is passed on to the backend, and any further 

data from either client or backend is passed on unaltered until either end closes the connection.

当进入pipe模式时调用,在这个模式下,请求被送到后端服务器,之后的的所有客户端与服务器端的请求将一直以同样的方式传输,直到连接关闭。

The vcl_pipe subroutine may terminate with calling return() with one of the following keywords:

vcl_pipe子程序可以通过调用以下关键字通过return()来终止处理:

error code [reason]  Return the specified error code to the client and abandon the request.

pipe Proceed with pipe mode.

vcl_pass

Called upon entering pass mode. In this mode, the request is passed on to the backend, and the

 backend's response is passed on to the client, but is not entered into the cache. Subsequent requests sub‐ mitted over the same client connection are handled normally.

进入pass模式时调用,在这个模式下,请求被直接送到后端,后端返回的数据被直接返回到客户端,并且不加入缓存中,之后的请求将以同样的方式加以处理。

The vcl_pass subroutine may terminate with calling return() with one of the following keywords:

vcl_piass子程序可以通过调用以下关键字通过return()来终止处理:

error code [reason]  Return the specified error code to the client and abandon the request.

pass  Proceed with pass mode.

restartRestart the transaction. Increases the restart counter. If the number of restarts is higher than 

max_restarts varnish emits a guru meditation error.

restart 重新开始事务。增加重启计数器,如果计数器的值大于max_restarts指定的值,varnish发出一个严重错误。

vcl_hash

You may call hash_data() on the data you would like to add to the hash.

你可以在你想加入hash的数据中去调用hash_data().

The vcl_hash subroutine may terminate with calling return() with one of the following keywords:

vcl_hash子程序可以通过调用以下关键字通过return()来终止处理:

hash Proceed.

hash 开始hash数据。

vcl_hit

Called after a cache lookup if the requested document was found in the cache.

如果数据从缓存中找到则调用vcl_hit.

The vcl_hit subroutine may terminate with calling return() with one of the following keywords:

vcl_hit子程序可以通过调用以下关键字通过return()来终止处理:

deliver  Deliver the cached object to the client. Control will eventually pass to vcl_deliver.

deliver 把缓存命中的数据传送给客户端 ,控制权将最终交给vcl_deliver.

error code [reason]   Return the specified error code to the client and abandon the request.

pass   Switch to pass mode. Control will eventually pass to vcl_pass.

restart  Restart the transaction. Increases the restart counter. If the number of restarts is higher than 

max_restarts varnish emits a guru meditation error.

vcl_miss

Called after a cache lookup if the requested document was not found in the cache. Its purpose is to 

decide whether or not to attempt to retrieve the document from the backend, and which backend to use.

如果数据没有从缓存中找到则调用vcl_miss.它的目的是决定是否尝试从后端服务器检索数据,如果有多个后端服务器的话,决定调用哪个后端服务器。

The vcl_miss subroutine may terminate with calling return() with one of the following keywords:

vcl_miss子程序可以通过调用以下关键字通过return()来终止处理:

error code [reason]  Return the specified error code to the client and abandon the request.

pass   Switch to pass mode. Control will eventually pass to vcl_pass.

fetch  Retrieve the requested object from the backend. Control will eventually pass to vcl_fetch.

fetch 从后端服务器检索数据,控制权将最终交给vcl_fetch.

vcl_fetch

Called after a document has been successfully retrieved from the backend.

当数据成功的从后端服务器检索到之后调用。

The vcl_fetch subroutine may terminate with calling return() with one of the following keywords:

vcl_fetch子程序可以通过调用以下关键字通过return()来终止处理:

deliver  Possibly insert the object into the cache, then deliver it to the client. Control will eventually 

pass to vcl_deliver.

deliver 尽可能的把数据加入缓存,然后传输给客户端 ,控制权将最终交给vcl_deliver.

error code [reason]    Return the specified error code to the client and abandon the request.

hit_for_pass  Pass in fetch. This will create a hit_for_pass object. Note that the TTL for the hit_for_pass 

object will be set to what the current value of beresp.ttl. Control will be handled to vcl_deliver on the 

current request, but subsequent requests will go directly to vcl_pass based on the hit_for_pass object.

hit_for_pass 进入fetch.它将创建一个hit_for_pass对象,hit_for_pass对象的TTL值将会被设置成beresp.ttl的当前值。该请求的控制权将交给vcl_deliver来处理,之后请求将直接交给vcl_pass,取决于hit_for_pass对象。

restart  Restart the transaction. Increases the restart counter. If the number of restarts is higher 

than max_restarts varnish emits a guru meditation error.

vcl_deliver

Called before a cached object is delivered to the client.

在数据传输到客户端之前被调用。

The vcl_deliver subroutine may terminate with one of the following keywords:

vcl_deliver子程序可以通过调用以下关键字通过return()来终止处理:

deliver  Deliver the object to the client.

deliver 把对象传输到客户端。

error code [reason]   Return the specified error code to the client and abandon the request.

restart   Restart the transaction. Increases the restart counter. If the number of restarts is higher 

than max_restarts varnish emits a guru meditation error.

vcl_error

Called when we hit an error, either explicitly or implicitly due to backend or internal errors.

The vcl_error subroutine may terminate by calling return with one of the following keywords:

vcl_error子程序可以通过调用以下关键字通过return()来终止处理:

deliver  Deliver the error object to the client.

restart   Restart the transaction. Increases the restart counter. If the number of restarts is higher than 

max_restarts varnish emits a guru meditation error.

vcl_fini

Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.

return() values:

ok Normal return, VCL will be discarded.

------------------------------------------

启动脚本
#!/bin/bash
### BEGIN INIT INFO
# Author: JeremyWei
# Date: 2011.8.27
# Description: Varnish management
### END INIT INFO

prefix=/usr/local/varnish
varnish_bin=${prefix}/sbin/varnishd
storage=2000M
varnish_opts="-f ${prefix}/etc/varnish/default.vcl -T 127.0.0.1:2000 -a 0.0.0.0:80 -s file,/tmp,${storage}"

case "$1" in
    start)
        echo -n "Starting varnish......"

        $varnish_bin $varnish_opts

        if [ "$?" != 0 ] ; then
            echo " failed"
            exit 1
        else
            echo " done"
        fi
        ;;

    stop)
        echo -n "Shutting down Varnish......"

        pkill varnishd

        if [ "$?" != 0 ] ; then
            echo " failed"
            exit 1
        else
            echo " done"
        fi
        ;;

    restart)
        $0 stop
        $0 start
        ;;

    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

Subroutine列表
•vcl_recv
在请求开始时候被调用,在请求已经被接收到并且解析后调用。目的就是决定是否处理这个请求,怎么处理,使用哪个后端。vcl_recv以return结束,参数可以为如下关键字:
error code [reason]:返回错误码给客户端,丢弃请求。
pass:转换到pass模式。控制权最后会转移到vcl_pass。
pipe:转换到pipe模式。控制权最后会转移到vcl_pipe。
lookup:在缓存中寻找请求对象。控制权最后会转移到vcl_hit或者vcl_miss,决定于对象是否在缓存中。
•vcl_pipe
当进入pipe模式的时候被调用。在这个模式中,请求会被转移到后端,后续的数据不管是从客户端还是后端来的都会以不变的方式传送,直到连接关闭为止。vcl_pipe以return结束,参数可以为如下关键字:
error code [reason]:返回错误码给客户端,丢弃请求。
pipe:以pipe模式执行。
•vcl_pass
当进入pass模式的时候会被调用。在这个模式中,请求会被传送到后端,然后后端的响应会被传送回客户端,但是响应不会进入缓存中。接下来通过相同客户端连接发起的请求会以普通的方式来处理。vcl_pass以return结束,参数可以为如下关键字:
error code [reason]:返回错误码给客户端,丢弃请求。
pass:以pass模式执行。
restart:重新启动这个事务。增加了重启计数。如果重启的次数高于max_restarts,varnish会引起一个错误。
•vcl_hash
你如果把想把数据加入到hash中,那么调用hash_data()。vcl_hash以return结束,参数可以为如下关键字:
hash:执行hash逻辑。
•vcl_hit
如果请求的对象在缓存中被找到了,那么在缓存查找结束后被调用。vcl_hit以return结束,参数可以为如下关键字:
deliver:deliver缓存对象到客户端。控制权最后会转移到vcl_deliver。
error code [reason]:返回错误码给客户端,丢弃请求。
pass:切换到pass模式。控制权最后会转移到vcl_pass。
restart:重新启动这个事务。增加了重启计数。如果重启的次数高于max_restarts,varnish会引起一个错误。
•vcl_miss
如果请求的对象在缓存中没有被找到,那么在缓存查找结束后被调用。目的是为了决定是否去后端获取这个请求对象,并且要选择哪个后端。vcl_miss以return结束,参数可以为如下关键字:
error code [reason]:返回错误码给客户端,丢弃请求。
pass:切换到pass模式。控制权最后会转移到vcl_pass。
fetch:去后端获取请求对象。控制权最后会转移到vcl_fetch。
•vcl_fetch
当一个对象被成功从后端获取的时候此方法会被调用。vcl_fetch以return结束,参数可以为如下关键字:
deliver:可能把对象放入缓存中,然后再deliver到客户端。控制权最后会转移到vcl_deliver。
error code [reason]:返回错误码给客户端,丢弃请求。
esi:以ESI形式来处理刚刚被获取到的对象。
pass:切换到pass模式。控制权最后会转移到vcl_pass。
restart:重新启动这个事务。增加了重启计数。如果重启的次数高于max_restarts,varnish会引起一个错误。
•vcl_deliver
当一个缓存的对象被deliver到客户端的时候,此方法会被调用。vcl_deliver以return结束,参数可以为如下关键字:
deliver:发送对象到客户端。
error code [reason]:返回错误码给客户端,丢弃请求。
restart:重新启动这个事务,增加重启计数。如果重启的次数高于max_restarts,varnish会引起一个错误。
•vcl_error
当遇见一个错误的时候会被调用,错误可能是跟后端有关系或者内部错误。vcl_error以return结束,参数可以为如下关键字:
deliver:发送对象到客户端。
restart:重新启动这个事务,增加重启计数。如果重启的次数高于max_restarts,varnish会引起一个错误。

重要变量

subroutine不带参数,一般通过全局变量来实现信息的传递。

如下变量在backend中有效:
•.host:backend的主机名或者IP。
•.port:backend的端口。

如下变量在处理一个请求(例如vcl_recv)的时候可用:
•client.ip:客户端IP地址。
•server.hostname:服务器的主机名。
•server.identity:服务器标示,当启动varnish的时候用”-i”参数来指定。如果varnish启动时候没有指定”-i”参数,那么server.identity会被设置为用”-n”参数所指定的实例名称。
•server.ip:服务器IP地址。
•server.port:服务器端口。
•req.request:请求类型(例如“GET”,“HEAD”)。
•req.url:请求的URL。
•req.proto:HTTP协议版本。
•req.backend:处理请求的后端服务器。
•req.backend.healthy:后端是否健康。health check需要在backend的probe中进行设置。
•req.http.header:相关的HTTP头。
•req.hash_always_miss:强迫对于本次请求的缓存查找结果为miss。如果设置为”true”,那么varnish将会忽略任何存在的缓存对象,一直从后端重新获取资源。
•req.hash_ignore_busy:在缓存查找时候忽略任何忙的对象。如果有两个服务器,彼此互相查找缓存内容,那么可以使用这个变量来避免潜在的死锁。

如下变量在准备一个后端请求(比如在cache miss或者pass,pipe模式)的时候可用:
•bereq.request:请求的类型(比如“GET”,“HEAD”)。
•bereq.url:请求的URL。
•bereq.proto:与后端服务器交互的HTTP协议版本。
•bereq.http.header:相关的HTTP头。
•bereq.connect_timeout:与后端连接的超时时间。
•bereq.first_byte_timeout:从后端返回第一个字节所需等待的秒数,在pipe模式中不可用。
•bereq.between_bytes_timeout:从后端返回的每个字节之间的时间间隔,以秒计。在pipe模式中不可用。

如下的变量在请求对象从后端返回之后,在其被放入缓存之前可用。换句话说,也就是在vcl_fetch中可用。
•beresp.proto:HTTP协议版本。
•beresp.status:后端返回的HTTP状态码(例如200,302等)。
•beresp.response:后端返回的状态内容(例如“OK”,“Found”)。
•beresp.cacheable:如果请求的结果是可以被缓存的,那么此变量为”true”。如果HTTP状态码为200, 203, 300, 301, 302, 404,410之一并且pass没有在vcl_recv中被调用,那么这个结果就是可以被缓存的。如果response的TTL和grace time都为0,那么beresp.cacheable将会为0。beresp.cacheable是可写的。
•beresp.ttl:缓存对象的生存时间,以秒为单位,这个变量是可写的。

在对象已经存在于缓存中并被查询到的时候,一般在vcl_hit和vcl_deliver中,如下的变量(大部分是read-only)可用:
•obj.proto:与后端交互的HTTP版本协议。
•obj.status:后端返回的HTTP状态码。
•obj.response:后端返回的HTTP状态内容。
•obj.cacheable:如果对象的beresp.cacheable为”true”,那么此变量的值为”true”。除非你强制delivery,否则obj.cacheable一直为”true”。
•obj.ttl:缓存对象的生存时间,以秒为单位,这个变量是可写的。
•obj.lastuse:从现在到对象最近一次访问所间隔的时间,以秒为单位。
•obj.hits:对象被发送到客户端的次数,0表示缓存查询miss了。

如下变量在决定对象hash key的时候可用:
•req.hash:hash key被用来关联一个缓存中的对象。在读写缓存的时候都会被用到。

如下变量在准备把一个响应发送给客户端时候可用:
•resp.proto:响应使用的HTTP协议版本。
•resp.status:将要返回的HTTP状态码。
•resp.response:将要返回的HTTP状态内容。
•resp.http.header:相关的HTTP头。

Varnish 配置与管理

管理varnish以及清除内存等操作虽然可以使用varnishadm,但是这里推荐使用telnet,一个交互的管理界面。

比如: telnet 127.0.0.1 6082

之后,输入help会显示所有可用命令。

help [command] ping [timestamp] status
start
stop
stats
vcl.load
vcl.inline
vcl.use
vcl.discard
vcl.list
vcl.show
param.show [-l] [] param.set
quit
purge.url
purge.hash
purge    [&&   ]...
purge.list

重新加载Varnish配置文件

telnet 127.0.0.1 6082 vcl.load newconfig /data/app/varnish/etc/varnish/default.vcl
vcl.use newconfig

注意:varnish 的CLI可能需要认证,最简单的办法就是在varnish启动的时候取掉相应的参数。

-S /etc/varnish/secret \

参考 https://www.varnish-cache.org/docs/trunk/reference/varnish-cli.html

Varnish的缓存方式

Malloc (malloc) 通过 malloc 获取内存,简单,速度快

Mmap file (file) 创建文件缓存

这个是varnish缓存的两种方式,可以在启动的时候通过参数指定。

Varnish处理流程

首次请求时过程如下:

recv->hash->miss->fetch->deliver

缓存后再次请求:

recv->hash->hit->deliver(fetch的过程没了,这就是我们要做的,把要缓存的页面保存下来)

直接交给后端pass的情况:

recv->hash->pass->fetch->deliver(直接从后端获取数据后发送给客户端,此时Varnish相当于一个中转站,只负责转发)

VCL以及基本对象

request 从客户端进来

responses 从后端服务器过来

object 存储在cache中

VCL语言

req 请求目标,当varnish接收到一个请求,这时req object就被创建了,你在vcl_recv中的大部分工作,都是在req object上展开的。

beresp 后端服务器返回的目标,它包含返回的头信息,你在vcl_fetch中的大部分工作都是在beresp object上开展的。

obj 被cache的目标,只读的目标被保存于内存中,obj.ttl的值可修改,其他的只能读。

VCL支持一下运算符

= 赋值运算符

== 对比

~ 匹配,在ACL中和正则表达式中都可以用

! 否定

&& 逻辑与

|| 逻辑或

Grace mode

如果后端需要很长时间来生成一个对象,这里有一个线程堆积的风险。为了避免这 种情况,你可以使用 Grace。他可以让 varnish 提供一个存在的版本,然后从后端生成新 的目标版本。

当同时有多个请求过来的时候,varnish只发送一个请求到后端服务器,在“set beresp.grace = 30m; ”时间内复制旧的请求结果给客户端。

Saint mode

有时候,服务器很古怪,他们发出随机错误,您需要通知 varnish 使用更加优雅的方式处理 它,这种方式叫神圣模式(saint mode)。Saint mode 允许您抛弃一个后端服务器或者另一 个尝试的后端服务器或者 cache 中服务陈旧的内容。

sub vcl_fetch {  if (beresp.status == 500) {   set beresp.saintmode = 10s;
  restart;
 }  set beresp.grace = 5m;}

Varnish代理

########
backend default {
  .host = "192.168.0.12";
  .port = "8080";
}
#现在添加一个新的backend服务器
backend test {
  .host = "192.168.0.12";
  .port = "8000";
}
#要定义特殊的url被发送到哪里sub vcl_recv {
  if (req.url ~ "^/abcd/") {
    set req.backend = test;
  } else {
    set req.backend = default;
  }
}

Varnish负载均衡

可以把多台 backends 聚合成一个组,这些组被叫做directors。这样可以增强性能和弹力。您可以定义多个backends和多个group在同一个directors。

backend server1 {
    .host = "192.168.0.1" ;
    .port = "8080" ;
}
backend server2 {
    .host = "192.168.0.2" ;
    .port = "8080" ;
}
director drupal001 round-robin {
    { .backend = server1; }
    { .backend = server2; }
}sub vcl_recv {
   if (req.http.host !~ "www\.drupal001\.com$"){
      error 404 "Unknown HostName!";
    }
    set req.backend = drupal001;
 }

健康检查

在之前的两个后端服务器上加上健康检查。

backend server1 {
    .host = "192.168.0.1" ;
    .port = "8000" ;
    .probe = {
      .url = "/";       #哪个 url需要varnish请求。
      .interval = 5s;   #检查的间隔时间。
      .timeout = 1 s;   #等待多长时间探针超时。
      .window = 5;      #维持5个sliding window的结果。
      .threshold = 3;   #至少有三次window是成功的,就宣告bachend健康。
     }
}

主备

后端备份。在recv里增加了
if (req.restarts == 0) {
    set req.backend = backend1;
} else  {
    set req.backend = backend2;
}
在fetch里增加了
if (beresp.status != 200 && req.restarts == 0) {
    restart;
}
或在error里加restart

重点参考https://www.varnish-cache.org/docs/3.0/reference/vcl.html

注意事项:

1. Varnish的不同版本的配置不同,必须查阅官方文档。

比如,在2.x 直接用ESI表示启用ESI,在3.x就不是了。

2. Varnish 2.x有Cookie的问题,当Cookie过大,会产生503错误,升级varnish或者减少set_cookie的操作。

3. 启动varnishd的时候如果选用-s file方式,每次会重新建立缓存文件,而原来的文件不会删除,因此注意清除这些遗留文件。

注释完整的一段VCL文件参考

 

#设置后端服务器地址
backend default {
     .host = "127.0.0.1";
     .port = "80";
}
 
#允许刷新缓存的ip
acl purgeAllow {
     "localhost";
     "192.168.56.1";
}
 
sub vcl_recv {
     #刷新缓存设置
     if (req.request == "PURGE") {
          #判断是否允许ip
          if (!client.ip ~ purgeAllow) {
               error 405 "Not allowed.";
          }
          #去缓存中查找
          return (lookup);
     }
 
     #首次访问增加X-Forwarded-For头信息,方便后端程序
     #获取客户端ip
     if (req.restarts == 0) {
          #如果设置过此header则要再次附加上,用,隔开,如果
          #只有一层代理的话,就无需设置了
          if (req.http.x-forwarded-for) {
               set req.http.X-Forwarded-For =
                    req.http.X-Forwarded-For ", " client.ip;
          }
          #没有则要加上
          else {
               set req.http.X-Forwarded-For = client.ip;
          }
     }
 
     #修正客户端的Accept-Encoding头信息,默认选用gzip方式
     #防止个别浏览器发送类似 deflate, gzip
     #当然后端如果只支持gzip的话.可以只设置gizp
     if (req.http.Accept-Encoding) {
          if (req.http.Accept-Encoding ~ "gzip") {
               set req.http.Accept-Encoding = "gzip";
          }
          #如果后端支持deflate方式,建议去掉,否则刷新缓存时
          #需特殊处理
          elsif (req.http.Accept-Encoding ~ "deflate") {
               set req.http.Accept-Encoding = "deflate";
          }
          #其他的压缩方式忽略
          else {
               remove req.http.Accept-Encoding;
          }
     }
 
     #静态文件和明确以.php结尾的url无需缓存, 建议把静态文件分离
     #至单独服务器下,减少动态应用服务器压力,同时降低arnishd的压力
     if(req.url ~ "\.(png|gif|jpg|css|js|php)$"){
          return (pass);
     }
 
     #非正规的请求直接转发给后端服务器
     if (req.request != "GET" &&
          req.request != "HEAD" &&
          req.request != "PUT" &&
          req.request != "POST" &&
          req.request != "TRACE" &&
          req.request != "OPTIONS" &&
          req.request != "DELETE") {
          /* Non-RFC2616 or CONNECT which is weird. */
          return (pipe);
     }
 
     #只处理GET和HEAD请求,如果你不想缓存POST的页面话
     if (req.request != "GET" && req.request != "HEAD") {
          return (pass);
     }
     #http认证的页面也pass
     if (req.http.Authorization) {
          return (pass);
     }
 
     return (lookup);
}
 
#管道?按官方文档说的是此模式下请求会原封不动的转交给后端知道连接关闭
sub vcl_pipe {
     return (pipe);
}
 
#交给后端服务器
sub vcl_pass {
    return (pass);
}
 
#缓存文件名的哈希处理
sub vcl_hash {
     #以url为hash
     set req.hash += req.url;
     #加上host
     if (req.http.host) {
          set req.hash += req.http.host;
     }
     #没有则取ip
     else {
          set req.hash += server.ip;
     }
     #支持压缩的要增加,防止发送给不支持压缩的浏览器压缩的内容
     if(req.http.Accept-Encoding){
          set req.hash += req.http.Accept-Encoding;
     }
     return (hash);
}
 
#缓存命中后的处理
sub vcl_hit {
     #如果不可缓存,直接交给后端
     if (!obj.cacheable) {
          return (pass);
     }
     #如果为更新缓存的请求,则设置ttl为0,并告知客户端处理结果
     if (req.request == "PURGE") {
          set obj.ttl = 0s;
          error 200 "Purged.";
     }
 
     set resp.http.X-Cache = "HIT“
     return (deliver);
}
 
#缓存未命中
sub vcl_miss {
     #更新缓存的请求,提示缓存不存在Not in cache
     if (req.request == "PURGE") {
          error 404 "Not in cache.";
     }
     #既然缓存不存在了,就去后端取吧
     return (fetch);
}
#
sub vcl_fetch {
 
     #是否开启ESI功能(仅做演示用,单独给/esi-test.html开启esi)
     if (req.url == "/esi-test.html") {
          esi;
     }
 
     #如果后端返回不可缓存,直接pass
     if (!beresp.cacheable) {
          return (pass);
     }
 
     #/article/下的url缓存30分钟(演示用)
     if (req.url ~ "^/article/\d+\.html$"){
          set beresp.ttl = 30m;
     }
 
     #/category/下的url缓存20分钟(演示用)
     if (req.url ~ "^/category/$"){
          set beresp.ttl = 20m;
     }
 
     #如果后端发送了set-cookie头信息(如session会话开启),则不缓存
     if (beresp.http.Set-Cookie) {
          return (pass);
     }
 
     return (deliver);
}
 
#发送给客户端
sub vcl_deliver {
     #去掉varnish中的一些头信息(如果你不想保留的话,建议保留Age,方便查看)
     #remove resp.http.X-Varnish;
     #remove resp.http.Via;
     return (deliver);
}
 
#定义错误页面的信息
sub vcl_error {
     #设置返回页面的类型及编码
     set obj.http.Content-Type = "text/html; charset=utf-8";
     #具体内容,可以更加自己的需要修改错误提示信息
     synthetic {"
       HTTP ERROR
    "};
     return (deliver);
}

官方文档

非常重要,必须参考。

https://www.varnish-cache.org/docs

官方示例 Example

https://www.varnish-cache.org/trac/wiki/VCLExamples

VCL2.x升级到3.0

https://www.varnish-cache.org/docs/3.0/installation/upgrade.html 

WIKI

https://www.varnish-cache.org/trac/ 

drupal on Varnish

https://www.varnish-cache.org/trac/wiki/VarnishAndDrupal 

 

 

 

http://www.drupal001.com/2011/12/varnish-drupal-basic/

php aes

/**
 * aes
 *
 */
class aes{
    private $key = "wt@36";
    private $iv         = "8401948501850295"; //只能是16字节
 
    /**
     * 
     * @param unknown_type $key
     * @param string $iv   16 length
     */
    function __construct($key,$iv=null){
        $this->key = $key;
        if (!empty($iv)){
         $this->iv = $iv;
        }
    }
 
    /**
     * 加密
     * @param string $value
     * @return string
     */
    function encrypt($value){
     return bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->key, $value, MCRYPT_MODE_CBC,$this->iv));
    }
    
    /*
     * AES解密
    */
    function decrypt($value){
     return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, pack("H*",$value),MCRYPT_MODE_CBC, $this->iv);
    }
}

关闭 Powered-By: PHP

X-Powered-By: PHP/5.x.x
可以在php.ini文件中设置:
; Decides whether PHP may expose the fact that it is installed on the server
; (e.g. by adding its signature to the Web server header).  It is no security
; threat in any way, but it makes it possible to determine whether you use PHP
; on your server or not.
; http://php.net/expose-php
expose_php = On #这里改成Off

这样就避免了输出类似 X-Powered-By: PHP/5.x.x 这样的信息

注: 有一些php版本包会把这样的信息写进源码里面,所以改源码后重新编译即可。

 

session.name  = phpsession 可修改其它

简单COOKIE读写

<script>
Cookie =
{
g : function(k) {return ((new RegExp(["(?:; )?",k,"=([^;]*);?"].join(""))).test(document.cookie)&&RegExp["$1"])||"";},
s : function(k,v,e,d) {document.cookie = [k,"=",v, e&&e["toGMTString"]?';expires='+e.toGMTString():"",";path=/;domain=",d||".mmmm.com"].join("");}
};
</script><script>
Cookie.g("tinfo").split("*").length == 2 ? Cookie.s("tinfo", Cookie.g("tinfo") + "*") : Cookie.s("tinfo", "", new Date(0));
</script><script>