vpn 网关&出口

VPN的英文全称是“Virtual Private Network”,翻译过来就是“虚拟专用网络”。顾名思义,虚拟专用网络可以把它理解成是虚拟出来的企业内部专线。

在公司外部internet,通过vpn拨号连接到单位的VPN后,就相当于这台电脑连接在了企业内部局域网中

单位的VPN 专用拨号,拨号链接正常,就是上不了网
每次新建这个拨号都正常,也能连到公司内部网上

这个问题的原因是默认情况下,连接VPN后,电脑的网关就会被修改成VPN设备那头的网关
所有上网的数据都默认通过VPN如果VPN设备没有设置转发外网数据的话,你就上不了网

所以启用本地默认网关,不使用“远程网络上的默认网关”就能访问远程局域网的同时,还能通过本地计算机访问Internet。

VPN连接-->属性--> 网络--> Internet协议--> 高级--> 勾掉“在远程网络上使用网关”

发表在 technologys | 标签为 | vpn 网关&出口已关闭评论

集群系统 heartbeat & lvs

一般我们用到的集群系统主要有2种:

1、高可用(High Availability)HA集群, 使用Heartbeat实现;也会称为”双机热备”, “双机互备”, “双机”。

2、负载均衡群集(Load Balance Cluster),使用Linux Virtual Server(LVS)实现;

 

heartbeat (Linux-HA)的工作原理:heartbeat最核心的包括两个部分,心跳监测部分和资源接管部分,心跳监测可以通过网络链路和串口进行,而且支持冗 余链路,它们之间相互发送报文来告诉对方自己当前的状态,如果在指定的时间内未受到对方发送的报文,那么就认为对方失效,这时需启动资源接管模块来接管运 行在对方主机上的资源或者服务。

另一种参考:  Keepalived

 

LVS详解:http://www.linuxidc.com/Linux/2012-09/71474.htm

http://linux.chinaunix.net/techdoc/net/2009/07/21/1125256.shtml

 

基于heartbeat v2和ldirectord实现director高可用

一、环境拓扑介绍

点击查看原图

说明:前端两台调度服务器Director1和Director2,两者之间可以实现故障转移,例如当Director1节点出现故障时Director2节点可以自动接管调度服务器的资源,能够继续为为客户端转发请求到后端Real Server;而且当后台的node1或着node2出现故障时能够把故障节点自动踢出列表,当恢复正常时能够自动加入。
注意:
      1、设置各个节点间的时间同步
      2、基于hosts文件实现能够互相用主机名访问
      3、使用uname -n执行结果要和主机名相同
      4、确保ipvsadm服务和httpd服务关闭开机启动
 
二、安装相关软件包
需要的软件:
 ipvsadm
 heartbeat                                        
 heartbeat-ldirectord                  
 heartbeat-pils                                
 heartbeat-stonith                    
 libnet          
 perl-MailTools                
 libtool-ltdl                
 openhpi-libs            
 perl-Compress-Zlib              
 perl-HTML-Parser            
 perl-HTML-Tagset            
 perl-TimeDate    
 perl-libwww-perl 
 
三、配置Director节点之间高可用
1、复制配置文件样例
[root@director1 ~]# cd /usr/share/doc/heartbeat-2.1.4/
[root@director1 heartbeat-2.1.4]# cp authkeys ha.cf haresources /etc/ha.d/
 
2、编辑配置文件
[root@director1 heartbeat-2.1.4]# cd /etc/ha.d/
[root@director1 ha.d]# vim ha.cf 
--------------------------添加如下行------------------------------------
bcast  eth1   //定义发送心跳信息的广播接口,我这里是eth1
node    director1 //定义节点
node    director2
-------------------------结束--------------------------------------------
 
编辑配置文件authkeys
[root@director1 ha.d]# vim authkeys    
-------------------------添加如下行---------------------------------
auth 1
1 md5 124hddhu56d8yd8  //后边的为随机数值
--------------------------结束-------------------------------------
[root@director1 ha.d]# chmod 600 authkeys  //设置权限为600 
 
编辑配置文件haresources
[root@director1 ha.d]# vim haresources    //编辑资源配置文件添加如下行
director1      192.168.56.200/32/eth1/192.168.56.200 ldirectord //定义资源VIP,ldirectord服务
 
编辑ldriectord配置文件
[root@director1 ha.d]# vim ldirectord.cf 
--------------------------------修改为以下内容----------------------------
checktimeout=3    //检测超时时间
checkinterval=1    //检测间隔
autoreload=yes    //该配置文件修改后能够自动重载
quiescent=yes 
virtual=192.168.56.200:80 //定义VIP地址和端口
        real=192.168.56.103:80 gate //定义real server的IP和端口
        real=192.168.56.104:80 gate //定义第二个real server
        fallback=127.0.0.1:80 gate //如果所有后端节点不可用时请求连接的转发位置,此处设置转发给director自身的80端口
        service=http    //定义服务类型
        request=".test.html" //检测后端节点时使用的页面
        receive="ok"    //检测的关键字,这里的设置表示测试访问.test.html页面是否包含ok关键字,如果有则说明该节点正常,否则认定为故障
        scheduler=wlc //指定算法
        protocol=tcp //定义协议为tcp
        checktype=negotiate //检测类型
        checkport=80    //检测的端口
-----------------------------------结束------------------------------------------
 
3、把配置文件拷贝到director2节点
[root@director1 ha.d]# scp -p ha.cf authkeys ldirectord.cf haresources director2:/etc/ha.d/

四、配置后端服务节点
 
安装apache配置测试主页
[root@node1 ~]# yum -y install httpd
[root@node1 ~]# echo node1 > /var/www/html/index.html
[root@node1 ~]# echo ok > /var/www/html/.test.html
配置节点的其他参数请参看LVS的文档介绍,这里执行在LVS文档中介绍的real server上执行的脚本(参见另外一篇博客:LVS负载均衡集群详解):
[root@node1 ~]# bash realserver.sh start
 
在node2上执行与node1节点相同的操作,为了演示方便可以看出效果在node2节点上的index.html页面输入与node1不同的内容以示区分。
 
五、启动heartbeat服务测试
[root@director1 ha.d]# service heartbeat start
[root@director1 ha.d]# ssh director2 'service heartbeat start' //director节点通过SSH启动heartbeat服务
 
测试Director1节点故障
[root@director1 ha.d]# /usr/lib/heartbeat/hb_standby //该脚本为heartbeat自带的脚本可以使该节点转为备用节点。

点击查看原图
 
测试node1节点故障
[root@node1 ~]# service httpd stop

点击查看原图

在director2节点上使用ipvsadm -Ln命令可以看到已经自动把node1节点相关条目移除

测试node1和node2节点同时故障,由于在ldirectord配置文件中设置了当所有后端节点故障时请求转发至director本身的80端口,所以这里需要director也安装httpd服务,或者修改该配置文件转向其他Web服务器。
 
总结:至此一个高可用的Director调度服务器集群已经完成,同时也要注意在现实环境中至少要2条线路来同时广播节点心跳信息,避免因为线路的故障造成节点间的资源争夺。

发表在 technologys | 标签为 , | 集群系统 heartbeat & lvs已关闭评论

北京 DNS

北京联通DNS服务器地址:
202.106.196.115
202.106.0.20
202.106.46.151(ADSL)
北京电信DNS服务器地址:
219.141.136.10
219.141.146.10

俄罗斯 / Russian :

Yandex.Dns Basic
77.88.8.8
77.88.8.1

Yandex.Dns Safe
77.88.8.88
77.88.8.2

Yandex.Dns Family
77.88.8.7
77.88.8.3

罗杰斯通信公司,加拿大 / ClearCloud:
174.118.212.1
174.118.212.2

发表在 technologys | 北京 DNS已关闭评论

iPhone消息推送机制实现与探讨

.NET 开源项目:

https://github.com/Redth/APNS-Sharp

Push的原理:

Push 的工作机制可以简单的概括为下图

点击查看原图

图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider。

APNS 是Apple Push Notification Service(Apple Push服务器)的缩写,是苹果的服务器。

上图可以分为三个阶段。

第一阶段:.net应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。

第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。

第三阶段:iPhone把发来的消息传递给相应的应用程序, 并且按照设定弹出Push通知。

 点击查看原图

从上图我们可以看到。

1、首先是应用程序注册消息推送。

2、 IOS跟APNS Server要deviceToken。应用程序接受deviceToken。

3、应用程序将deviceToken发送给PUSH服务端程序。

4、 服务端程序向APNS服务发送消息。

5、APNS服务将消息发送给iPhone应用程序。

无论是iPhone客户端跟APNS,还是Provider和APNS都需要通过证书进行连接的。下面我介绍一下几种用到的证书。

几种证书:

一、*.certSigningRequest文件

1、生成Certificate Signing Request (CSR):

点击查看原图

2、填写你的邮箱和Common Name,这里填写为PushChat。选择保存到硬盘。

点击查看原图

这样就在本地生成了一个PushChat.certSigningRequest文件。

二、生成*.p12文件

1、导出密钥,并输入你的密码。

点击查看原图

输入你的密码:

点击查看原图

这样就生成了一个PushChatKey.p12文件。

三、新建一个App ID 和SSL certificate文件

1、用你的付过费的apple帐号登录到iOS Provisioning Portal。新建一个App ID。

Description:中输入PushChat

Bundle Seed ID:默认选择Generate New

Bundle Identifier:输入com.mysoft.PushChat

点击提交

点击查看原图

这样就会生成下面这条记录:

点击查看原图

点击配置:

点击查看原图

出现下面界面,点击继续:

点击查看原图

这里我们选择前面生成好的PushChat.certSigningRequest文件,点击生成。

点击查看原图

正在生成

点击查看原图

生成完毕,我们把它下载下来。命名为aps_developer_identity.cer

点击查看原图

点击完成,你会发现状态变成Enabled。

点击查看原图

到现在为止,我们已经生成了3个文件。

1、PushChat.certSigningRequest

2、PushChatKey.p12

3、aps_developer_identity.cer

现在我们创建一个简单的iPhone应用程序。

1、打开Xcode,选择创建一个View-based Application。命名如下图:

点击查看原图

2、在PushChatAppDelegate中的didFinishLaunchingWithOptions方法中加入下面代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; // Let the device know we want to receive push notifications [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; return YES; }

通过registerForRemoteNotificationTypes方法,告诉应用程序,能接受push来的通知。

3、在xcode中运行,会弹出下面的提示框:

点击查看原图

选择OK。表示此应用程序开启消息通知服务。

在 PushChatAppDelegate.m代码中添加下面方法获取deviceToken :

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { NSLog(@"My token is: %@", deviceToken); } - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { NSLog(@"Failed to get token, error: %@", error); }

获取到的deviceToken,我们可以通过webservice服务提交给.net应用程序,这里我简单处理,直接打印出来,拷贝到.net应用环境中使用。

发送通知的.net应用程序出来需要知道deviceToken之外,还需要一个与APNS连接的证书。

这个证书可以通过我们前面生成的两个文件中得到。

使用OpenSSL生成.net和APNS通信的证书文件。

1、将aps_developer_identity.cer转换成 aps_developer_identity.pem格式。

openssl x509 -in aps_developer_identity.cer -inform DER -out aps_developer_identity.pem -outform PEM

2、将p12格式的私钥转换成pem,需要设置4次密码,这里密码都设置为:abc123。

openssl pkcs12 -nocerts -out PushChat_Noenc.pem -in PushChat.p12

3、用certificate和the key 创建PKCS#12格式的文件。

openssl pkcs12 -export -in aps_developer_identity.pem -inkey PushChat_Noenc.pem -certfile PushChat.certSigningRequest -name "aps_developer_identity" -out aps_developer_identity.p12

这样我们就得到了在.net应用程序中使用的证书文件:aps_developer_identity.p12

在.net应用程序中发送通知。

有个开源的类库:apns-sharp。

地址是:http://code.google.com/p/apns-sharp/

我们下载源代码,对里面的JdSoft.Apple.Apns.Notifications做相应的调整就能用了。

我们根据DeviceToken和p12File对JdSoft.Apple.Apns.Notifications.Test代码做相应的调整,如下图。

点击查看原图

这样就OK了。

效果:

通知的代码:

for (int i = 1; i <= count; i++) { //Create a new notification to send Notification alertNotification = new Notification(testDeviceToken); alertNotification.Payload.Alert.Body = string.Format("Testing {0}...", i); alertNotification.Payload.Sound = "default"; alertNotification.Payload.Badge = i; //Queue the notification to be sent if (service.QueueNotification(alertNotification)) Console.WriteLine("Notification Queued!"); else Console.WriteLine("Notification Failed to be Queued!"); //Sleep in between each message if (i < count) { Console.WriteLine("Sleeping " + sleepBetweenNotifications + " milliseconds before next Notification..."); System.Threading.Thread.Sleep(sleepBetweenNotifications); } }

用手机拍的ipad上面的显示:

点击查看原图点击查看原图

总结:这篇文章主要是详细的讲述了ios消息推送机制的实现,如何通过.net应用程序发送消息给ios应用程序。

 

附:

   摘自网上的一短代码: pingguo-C#.zip

发表在 technologys | 标签为 , , | iPhone消息推送机制实现与探讨已关闭评论

在Windows下安装BIND作为DNS服务器

1、下载BIND

http://ftp.isc.org/isc/bind9/9.4.3/BIND9.4.3.zip

2、安装
下载回来是zip的压缩包,解压以后直接双击BINDInstall.exe安装,默认安装路径是C:\WINDOWS\system32\dns。bind在win32下将自己注册成服务,服务名叫ISC BIND,程序名为named.exe,启动服务需要用一专有帐户,默认名称为named,密码由安装者自定义。点击install以后,程序便安装在C:\WINDOWS\system32\dns下,这时还不能启动bind服务,会报代号1067的错,得先经过配置。

3、配置
先运行命令行cmd,cd 至 C:\WINDOWS\system32\dns\bin下,运行rndc-confgen.exe -a,会自动在C:\WINDOWS\system32\dns\etc\下生成rndc.key。此rndc.key是在是bind 9.x版本的新功能,是有关DNS更新以及更新时加密处理的,跟我们个人用户无太大关系,不过基于兼容性,还是照做。接下来,在C:\WINDOWS\system32\dns\etc\下建立named.conf,即bind的配置文件,文件内容如下:

include "c:\windows\system32\dns\etc\rndc.key";
zone "." {
type hint;
file "c:\windows\system32\dns\etc\named.root";
};

include一行主要是将rndc.key包含进去,zone "."一行是设置根节点,我们做自己个人的DNS服务器,只要设置这个足够,其他的各个参数可以自己上网去搜索了解,够用就好接下来从http://www.internic.net/下载named.root文件,里面定义了全球的根DNS服务器,下载地址是http://www.internic.net/zones/named.root,需要定期更新,不过用dig工具也可以实时查得根DNS服务器的地址,只不过win32下没有直接将输出结果存为named.root文件的功能,所以还是下载比较方便。named.root文件也是放在etc目录下。如果C盘是NTFS格式的话,还要记得定义启动bind的named用户c:\windows\system32\dns\etc这个目录的完全控制权,不然,还是会报1067的错(如果bind不作为服务启动,直接在cmd里启动,权限不必放行,因为是直接用当前用户的权限嘛)

4、启动

从“计算机管理--》服务”启动ISC BIND服务。

5、测试

把网络上的任意一台机器的DNS设置到安装了BIND的机器IP。Ping一下www.google.com。如果通了,恭喜你,做对了。

发表在 technologys | 标签为 , | 在Windows下安装BIND作为DNS服务器已关闭评论

Android ADT 离线下载

网上很多的Android在IDE eclipse的开发环境教程,ADT的就安装肯定也在里面啦

ADT的安装都是一个在线安装地址

  https://dl-ssl.google.com/android/eclipse/

但是发现是这种在线安装方法不好,麻烦,时间长,所以都去找离线安装包啦,根据关键词,你可以找到ADT 12的zip下载地址:

http://dl.google.com/android/ADT-12.0.0.zip

但是我的eclipse 是最新版本的3.7.1,开发环境也要跟上吧,那现在ADT的最新版本是什么呢?

这里有一个技巧,那就是,可以利用在线安装地址获取当前适合eclipse 3.7.1的ADT版本,

点击查看原图

 

可以看到,当前在线安装的版本是16.0.1,最近更新时间是2011-12-15的,所以我们就下载最新的ADT ZIP包吧,

下载地址是什么?这个你应该可以猜出来了,我也算说的直白了。

http://dl.google.com/android/ADT-16.0.1.zip

有什么新版本你就可以用这个

http://dl.google.com/android/ADT-xx.x.x.zip来进行下载了

http://dl.google.com/android/ADT-20.0.3.zip

发表在 article | 标签为 | Android ADT 离线下载已关闭评论

VMWare Mac.OSX.10.6

介绍一下使用VMWare安装MAC OS X时,无需转换成ISO格式,直接使用MAC OS X的DMG镜像文件进行安装的方法。
安装必备:

硬件:一台拥有支持虚拟技术的64位双核处理器和2GB以上内存的PC。
VMware软件:太大我就不上传了,如需要请联系我!
DMG光盘镜像文件:太大我就不上传了,如需要请联系我!
引导镜像文件:http://u.115.com/file/e6rt4q7s darwin_snow_legacy.iso

http://u.115.com/file/dn9mb5ap 苹果引导darwin.iso

首先安装好VMWare Workstation 7.13。使用File->New->Virtual Machine创建一个虚拟机,在选择操作系统时选择Other->FreeBSD 64-bit。
点击查看原图

2011-8-15 22:03

CPU设置1核可以,2核也可以,如果你是双核CPU,建议你分配1个核;内存建议设置为1024MB,如果你的物理内存够大也可以多给些;硬盘最少分配15GB,太小则无法进行安装,如果你还想多装些软件,建议多分配一些。最后一步可以在Customize Hardware选项里把软驱删除,因为这个用不上。
创建好之后,需要你在刚建立的虚拟机目录下找到一个扩展名为.vmx的文件,用记事本打开,找到guestOS = "freebsd-64"一行,将引号里的freebsd-64改为darwin10,改完是guestOS = "darwin10",保存修改后的文件。 如下图:
点击查看原图

2011-8-15 22:03

做了这一步,在这个虚拟机的Options->General选项下就可以看到操作系统版本显示为:MAC OS X Server 10.6,如下图所示。仍显示为FreeBSD 64-bit的需要重启一下VMWare。
点击查看原图

2011-8-15 22:03

引导成功,现在是更换Mac镜像,然后按F5
点击查看原图

2011-8-15 22:03

添加镜像后,回车
点击查看原图

2011-8-15 22:03

经过一阵准备阶段就进入了苹果系统的安装过程,如下图所示:选择语言种类
点击查看原图

2011-8-15 22:03

在这里特别提一下,有的同学在进行到选择安装盘的步骤时看不到硬盘选项
点击查看原图

2011-8-15 22:03

不要着急,在屏幕上方的菜单中找到“实用工具”->“磁盘工具”,如图所示:
点击查看原图

2011-8-15 22:03

对你的虚拟硬盘执行“抹掉”操作,如图所示:
点击查看原图

2011-8-15 22:03

操作完成后关闭“磁盘工具”窗口就OK了,如图所示:
点击查看原图

2011-8-15 22:03

根据你的电脑配置不同,大概进行几十分钟的安装,你就可以用上苹果操作系统了。
点击查看原图

2011-8-15 22:03

点击查看原图

2011-8-15 22:03

点击查看原图

2011-8-15 22:03


看到下图的界面,表示你的系统已经安装完成,需要重新启动。
点击查看原图

2011-8-15 22:03

重新启动前你要特别注意,先要去掉安装时在CD/DVD(IDE)设备上加载的苹果DMG镜像,换上Darwin或者Rebel EFI引导镜像,否则你将不能成功引导安装好的MAC OS X系统。

发表在 article | VMWare Mac.OSX.10.6已关闭评论

彻底理解PHP的SESSION机制

1.session.save_handler = files



    
* 1. session_start()

         
1. session_start()是session机制的开始,它有一定概率开启垃圾回收,因为session是存放在文件中,

PHP自身的垃圾回收是无效的,SESSION的回收是要删文件的,这个概率是根据php
.ini的配置决定的,

但是有的系统是 session
.gc_probability = 0,这也就是说概率是0,而是通过cron脚本来实现垃圾回收。



            session
.gc_probability = 1

            session
.gc_divisor = 1000

            session
.gc_maxlifetime = 1440//过期时间 默认24分钟

            //概率是 session.gc_probability/session.gc_divisor 结果 1/1000, 

            //不建议设置过小,因为session的垃圾回收,是需要检查每个文件是否过期的。


            session.save_path = //好像不同的系统默认不一样,有一种设置是 "N;/path"

            //这是随机分级存储,这个样的话,垃圾回收将不起作用,需要自己写脚本




         
2. session会判断当前是否有$_COOKIE[session_name()];session_name()返回保存session_id的COOKIE键值,

这个值可以从php
.ini找到



            session
.name = PHPSESSID //默认值PHPSESSID

             



         
3. 如果不存在会生成一个session_id,然后把生成的session_id作为COOKIE的值传递到客户端.

相当于执行了下面COOKIE 操作,注意的是,这一步执行了setcookie()操作,COOKIE是在header头中发送的,

这之前是不能有输出的,PHP有另外一个函数 
session_regenerate_id() 如果使用这个函数,这之前也是不能有输出的。



                
setcookie(session_name(),

                          
session_id(),

                          session
.cookie_lifetime,//默认0

                          session.cookie_path,//默认'/'当前程序跟目录下都有效

                          session.cookie_domain,//默认为空

                          )



         
4. 如果存在那么session_id = $_COOKIE[session_name];

            然后去session
.save_path指定的文件夹里去找名字为'SESS_' . session_id()的文件.

            读取文件的内容反序列化,然后放到
$_SESSION中

    
* 2. 为$_SESSION赋值

      比如新添加一个值
$_SESSION['test'= 'blah'; 那么这个$_SESSION只会维护在内存中,当脚本执行结束的时候,

用把
$_SESSION的值写入到session_id指定的文件夹中,然后关闭相关资源.      这个阶段有可能执行更改session_id的操作,

比如销毁一个旧的的session_id,生成一个全新的session_id
.一半用在自定义 session操作,角色的转换上,

比如Drupal
.Drupal的匿名用户有一个SESSION的,当它登录后需要换用新的session_id



        
if (isset($_COOKIE[session_name()])) {

          
setcookie(session_name(), '', time() - 42000, '/');//旧session cookie过期

        }

        
session_regenerate_id();//这一步会生成新的session_id

       //session_id()返回的是新的值




      
3.写入SESSION操作

      在脚本结束的时候会执行SESSION写入操作,把
$_SESSION中值写入到session_id命名的文件中,可能已经存在,

可能需要创建新的文件。

    
* 4. 销毁SESSION

      SESSION发出去的COOKIE一般属于即时COOKIE,保存在内存中,当浏览器关闭后,才会过期,假如需要人为强制过期,

比如 退出登录,而不是关闭浏览器,那么就需要在代码里销毁SESSION,方法有很多,

          o 
1. setcookie(session_name(), session_id(), time() - 8000000, ..);//退出登录前执行

          o 2. usset($_SESSION);//这会删除所有的$_SESSION数据,刷新后,有COOKIE传过来,但是没有数据。

          o 3. session_destroy();//这个作用更彻底,删除$_SESSION 删除session文件,和session_id



      当不关闭浏览器的情况下,再次刷新,2和3都会有COOKIE传过来,但是找不到数据



2.session.save_handler = user



      用户自定义session处理机制,更加直观

    
* session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc'); 

1.session_start(),

      执行open(
$save_path, $session_name)打开session操作句柄

      
$save_path 在session.save_handler = files的情况下它就是session.save_path,

但是如果用户自定的话,这个两个参数都用不上,直接返回TRUE



      执行read(
$id)从中读取数据.//这个参数是自动传递的就是session_id(),可以通过这个值进行操作。

    * 2.脚本执行结束

      执行write(
$id, $sess_data//两个参数,很简单

    * 3.假如用户需要session_destroy()

      先执行destroy
.在执行第2步



      一个实际例子:



      
//SESSION初始化的时候调用

      function open($save_path, $session_name)

      {

        
global $sess_save_path;

        
$sess_save_path = $save_path;

        
return(true);

      }



      
//关闭的时候调用

      function close()

      {

        
return(true);

      }



      
function read($id)

      {

        
global $sess_save_path;

        
$sess_file = "$sess_save_path/sess_$id";

        
return (string) @file_get_contents($sess_file);

      }

      
//脚本执行结束之前,执行写入操作

      function write($id, $sess_data)

      {

        
echo "sdfsf";

        
global $sess_save_path;



        
$sess_file = "$sess_save_path/sess_$id";

        
if ($fp = @fopen($sess_file, "w")) {

          
$return = fwrite($fp, $sess_data);

          
fclose($fp);

          
return $return;

        } 
else {

          
return(false);

        }



      }



      
function destroy($id)

      {

        
global $sess_save_path;



        
$sess_file = "$sess_save_path/sess_$id";

        
return(@unlink($sess_file));

      }



      
function gc($maxlifetime)

      {

        
global $sess_save_path;



        
foreach (glob("$sess_save_path/sess_*"as $filename) {

          
if (filemtime($filename+ $maxlifetime < time()) {

            @
unlink($filename);

          }

        }

        
return true;

      }

发表在 php | 标签为 , | 彻底理解PHP的SESSION机制已关闭评论

常见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

发表在 db | 标签为 | 常见MySQL error code和SQLSTATE code已关闭评论

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。

发表在 db | 标签为 | mysql DECLARE已关闭评论

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()  线程安全

发表在 db | 标签为 | mysql 自增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

发表在 web server | 标签为 | iis7+ rewrite variable已关闭评论

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头。

发表在 web server | 标签为 | varnish 参数说明已关闭评论

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" &amp;&amp;
          req.request != "HEAD" &amp;&amp;
          req.request != "PUT" &amp;&amp;
          req.request != "POST" &amp;&amp;
          req.request != "TRACE" &amp;&amp;
          req.request != "OPTIONS" &amp;&amp;
          req.request != "DELETE") {
          /* Non-RFC2616 or CONNECT which is weird. */
          return (pipe);
     }
 
     #只处理GET和HEAD请求,如果你不想缓存POST的页面话
     if (req.request != "GET" &amp;&amp; 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/

发表在 web server | 标签为 | Varnish 配置与管理已关闭评论

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);
    }
}
发表在 php | 标签为 , | php aes已关闭评论