各种App Engine的简单比较

前段时间想要申请看一下新版的ACE,但是ACE的工程师不给我邀请码,说等到正式公开测试的时候亲自给我邀请码,然后我就信了~~~

但是,看到新版的ACE上面明明写的可以发邮件申请嘛~于是就发了封邮件;

下面简单的对比一下GAE和国内各种App Engine的特点;

GAE:GAE近来刚加入对PHP的支持,可以自行配置PHP.INI,有少量的禁用函数,相对来说使用起来还是非常灵活的。GAE的SQL是GOOGLE自己的CLOUD SQL,使用起来也比较方便;GAE PHP提供一定量的免费配额,CLOUD SQL是收费的。同时GAE PHP也继续支持了java所支持的TASKQUEUE memcache等,使用起来都比较方便,只是在国内需要绑定域名才能正常访问。
SAE:国内发展较早的APP ENGINE,开始的时候基本模仿GAE的一些特性,率先支持PHP;支持PHP是走在了GAE的前面,非常的不错。继承有来自GAE的特性如:MC,TASKQUEUE,CRON等也有自己的许多特色服务比如KVDB;而且支持mysql(RDC),这是GAE所未支持的
BAE:虽然走在了SAE的后面,但也是发展迅速,从正式对外公测到现在将近一年半的时间,发展成为一个较为不错的app engine;拥有memcache,taskqueue,消息服务,mysql(RDS),等等;还有BAE周边的一些服务,比如BCS,这个相对于SAE的Storage来说还是较为强大的
ACE:之前先是公测,后来不知道为什么改为了内测,现在还是内测;现在拿到了邀请码,发现功能还不是非常多,可能还正在进一步的开发和测试中吧。
上面的GAE,SAE,BAE都对本地写有限制,SAE做出了一个云商店,支持本地写,BAE做了一个类似远程磁盘(NFS)的解决方案,支持本地暂时写和永久写,但是都不是非常好的解决方案,也很期待ACE能够在本地写上面有一个非常好的解决方案。

闲说树洞

最近写了一个树洞的程序,这个树洞程序的功能在外看起来似乎就是一个普通的树洞程序,跟别人实现的效果差不多,能够在网页发布状态,然后将状态发送到人人网的公共主页;其实,这里面还是有不少地方值得研究和学习的。

在第一版的树洞程序中,实现了最基本的状态发布功能,可以通过网页将状态发布到人人网公共主页,并入库保存已发状态。在最初的时候,许多人担心会泄露个人信息,其实这个是绝对匿名的,因为网页没有登录,完全不知道这个发送的人是谁,最多也只能记录一下IP地址了。

在第一版上线之前,我就想到了,过滤器是必不可少的,如果没有过滤器,必然会有不少的垃圾信息,比如“sssssss” ,”11111111111111″,这样的垃圾信息,没有意义的信息,必然需要过滤掉,所以就写了一个过滤器,能够过滤掉多种垃圾信息,现在的过滤器依然是第一版的,因为第二部的过滤器正在构思中,还有就是目前用户量还不是很大,所以过滤器也没有必要太强大

【说一下过滤器吧】

目前过滤器能够过滤的主要信息:

1.纯数字性质的

2.纯字母的

3.空格的数量占百分比太高的

4.空的当然要过滤

5.没有中文的

6.标点符号占百分比太高的

7.字数太少或太多的

【再说一下时间限制吧】

因为API调用是有次数限制的,所以为了节省API开销,限制每个用户两次发送时间的间隔。

实现限制的原理很简单,就是一个MC的缓存过期问题,当用户欲发送消息的时候,先检测MC中是否有该用户发送消息的记录,如果有则返回拒绝发送;如果没有则设置一个具有有效期的缓存,然后发送该消息。网页版是基于IP的,微信版是基于微信平台发来的用户识别字串的。网页版基于IP会有一个问题,就是当在使用中国移动的网络发送的时候,因为移动IP的不足,所以对外的IP数量往往不多,会导致前一个用户发送完,另一个用户无法发送的问题。当然现在的用户量还比较少,所以就没有采取改进措施。

改进措施:可以在用户浏览器设置有效期很长的uuid为值的cookie,MC缓存设置的时候采用cookie传来的uuid作为键值。但如果只是采用uuid,如果用户伪造uuid还是可以破解限制的。目前没有想到更好的办法,或许可以设置限制单个IP每天的最大发送数量,然后再设置单个uuid的发送频繁程度会好一些吧。

【说一下微信平台】

微信平台当然少不了,毕竟用户数量是非常可观的,而且使用非常方便。

目前已经有一个简单的微信菜单了,现在的实现方法当然很简单,就是一个switch,可能刚开始学习C语言的小朋友都会了吧~

将来可能会有改进,改进方法是,先判断用户发来的信息字符数量是否很少且为字母,如果是的话就进入菜单流程,否则进入发送流程。

这样会有更好的用户体验,因为这样就可以在case里不存在的时候不进入发送流程,而是提示用户应该输入正确的菜单项了。

微信平台的问题:腾讯的用户数量非常大,微信平台的用户也很多,所以为了减少服务器压力,微信平台POST到我的服务器上之后只会停留5秒钟,如果5秒钟不能做出响应则挂机。

这个在晚上的时候还好,用户量较少,而且服务器负载较低,网络带宽也比较好,所以5秒钟足够可以完成处理用户请求并将消息POST到人人服务器上并在人人服务器返回发送成功之后给予微信以发送成功的响应。

但是到了白天,服务器压力提升,服务器curl外网的时候带宽有限,会有少数情况下超时,导致5秒钟内没有给微信平台响应,微信挂机,导致用户无法接收到发送成功的消息。

解决措施:为解决这个问题,我打算加入一个任务队列,当用户发起发送消息的请求的时候,先使用过滤器对其进行过滤,如果没有问题,就将发送任务推入队列,并提示用户正在发送,稍后查看之类的提示,这样就可以在5秒钟之内给予用户响应,增强用户体验。

【说说我的具体宣传方法吧】

说起这个宣传,我可是花了比写这个树洞更多的时间,首先是刚开始的时候许多童鞋不知道这是什么,可以做什么;然后就是如果从心理上接受树洞;然后就是如果让更多的人知道。

为此,我花了时间研究了最近在QQ空间传的非常火的几个图片。这个图片在每个人的QQ空间里看都是自己的QQ和昵称,也有IP地址所在的位置等。

经过分析发送,这个图片一个外链图片。本来一个外链图片很正常啊,但是这个图片不是普通的图片,另外QQ空间为了防止外链,往往喜欢将图片拉取到自己的服务器上做成缩略图。所以如果是一个普通的外链图片,会被腾讯图片服务器cgi程序拉取并将其存到自己的图库里。这样用户看图片的时候就是从自己的图库取图。但是这个外链图片似乎不是这么简单,经过分析发现,该图片的链接经过HTMLENCODE,这种方式的编码是将英文字母也进行的编码,但对于斜线不编码/ ,然后再进行了一次urlencode,这样之后再用腾讯的图像代理取一下,就可以解析图片了,而且始终是外链的图片,不会被缩略。

那如何能够显示用户的QQ昵称和地理位置呢?

这个就要使用到referer技术了。其实referer也不是什么技术,就是很简单的一个能够知道到达该网页的前一个网页的地址的方法。经过研究发现, 在QQ空间中的所有图片的referer都是QQ空间的url,其中会包含QQ号码,所有只要看吧,当前显示图片的url是谁的QQ,那么图片就会显示谁的QQ和昵称。

说到昵称,那昵称是如何获取到的呢?

这个用的是QQ空间的一个接口,可以通过调用该接口,通过QQ号码获取到该用户的一些简单信息。比如昵称,因为昵称不需要保密啊~

IP地址当然就很容易获取到了,所以获取到这些足够的信息就足以来显示一张图片了。然后我就找同学写了一段很文艺的话做了一个模板,这个模板很好啊,第一个位置是昵称,第二个位置是QQ,还可以加入地址,显得高端吧,每个人看到的都是自己,都以为是说自己的呢?真的很神奇,我也感到很神奇!!!

我是多么的崇拜第一个发现QQ空间的这个小小小漏洞的(也算不上什么漏洞的了嘛~),然后模仿这个,我又造了一个人人网的宣传画,原理是一样的。

【还是说一下人人网的吧】

人人网的这个虽然原理是一样的,但是还有许多的技术细节。比如:如果让这张图片显示呢?

最后发现,在人人网分享链接的时候会自动把网页中的图片拉取过来作为一个小图片显示。好的,那既然这样就可以利用了。

看看referer,不错有的哦~那按照上面QQ空间的方法来实现即可。

但是之后发现,当再次分享的时候,就会失效,为什么呢?因为人人网会在第二个用户分享相同的链接的时候把该图片缩略,好吧,这个比腾讯厉害了点,而且每一个分享该相同链接的人的缩略图地址都是一样的,好神奇!!!

那这样只好让每个人的链接都不一样才能起到宣传的目的了!!

好吧,为了让每个人的链接都不一样,我不希望每个人都给建立一个单独的文件,所以就用了主机重写,也就是url rewrite,这个就方便了,将所有用户的请求都重写到一个文件上不就OK 了吗?

是的,确实这样,但是还有许多的技术细节。如果感兴趣的话可以自己去看我的实现,当然如果你不会curl那可就惨了,因为你根本就看不到。。。网页会跳转的….我想这个对于从业多年的老鸟应该没什么难度吧,当然我也相信你也可以的~因为我就不是从业多年~~哈~娱乐一下的~

好了继续写:

大部分的功能都已经实现了,恩恩,我打算在学校里的墙上画一幅宣传画……能不能实现呢?呜呜,这个可不知道了,或许我需要在深夜里偷偷的找个艺术很好的童鞋,偷偷摸摸的跑到墙角下去画吧~哈~

 

 

PHP进行子域名探测

因为不会bash,所以只好用PHP了,因为发现阿里云数据库可能存在的漏洞,这个脚本就是用来探测阿里云数据库所有的子域名。

<?php

/*
 * @author:CplusHua
 * @date:2013-4-27
 * @version:1.0.0
 * @URI:http://www.219.me
 */
$code=Array();
$j=48;
$bool=TRUE;
for($i=0;$i<36;$i++){
    $code[$i]=  chr($j++);
    if($j>57&&$bool){
        $j=97;
        $bool=FALSE;
    } 
}
print_r($code);
$arr=Array('0','0','0','0','0','0','0','0','0','0','0','0','0','0','0');
$domain='';
while(1){
    $domain='';

    for($s=0;$s<15;$s++){
        $domain.=$code[$arr[$s]];
    }
    $host=$domain.".mysql.aliyun.com";
    //echo $host;

    ping($host);
    $arr[0]++;
    for($i=0;$i<14;$i++){
        if($arr[$i]>35){
            $arr[$i]=0;
            $arr[$i+1]++;
        } 
    }
     if(10==$arr[14]){
            break;
      }
}
function ping($host){
    return system('ping -c 1 '.$host.">> ping.txt 2>>/dev/null");
}

?>

快速切换Nginx作为网站前端代理服务器

Nginx比起Apache的高性能高并发特性已经被广泛的应用于生产环境中,如果网站原来使用的是Apache,那如何快速的将Nginx作为前端代理服务器来提供服务呢?

使用一个非常简单的配置文件配置即可。这里摒弃复杂的切换,和生产环境中要考虑的其他诸多因素,单纯简单讲解实现方法。

找到Nginx配置文件,一般位于/usr/local/nginx/conf中,名字为nginx.conf,为了测试,先不改动Apache的任何配置,将Nginx服务在81端口。

找到server配置,修改为以下配置,其中的website.com是网站的域名

server {
        listen       81;
        server_name  website.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass http://website.com;
            #root   html;
            #index  index.html index.htm;
        }

为了安全,我们可以先测试一下配置文件是否有语法错误

执行下面的命令测试语法是否正确

sudo /usr/local/nginx/sbin/nginx -t

如果正确将会显示类似下面的内容

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

为什么一定要测试配置文件是否正确呢?

1.Nginx配置文件的每一行后面都有一个分号,许多初次使用者会忘记添加分号,此时可能会出现一些莫名其妙的错误,比如提示缺少括号 }
2.Nginx运行时配置文件错误的载入可能会导致进程不受控制,即使使用stop命令都无法停止进程,所以一定要先测试配置文件是否正确
(ps:如果真的不受控制了,那只好强制杀死进程了,可以使用这条命令杀死进程 sudo killall nginx )

配置文件测试正确之后,reload配置文件即可使配置生效

sudo  /etc/init.d/nginx reload

配置文件已经成功载入
打开浏览器,输入上面配置的网站的域名(原来网站的域名)+端口号81,例如配置文件中给出的website.com,可以使用http://website.com:81来访问,这样之后就将Nginx设置为前端代理服务器了。
如果是Chrome浏览器,可以打开控制台,找到Network,查看加载的第一个文件的Response Header是否已经是Nginx
这里是我的截图,可以看到Server行已经变成Nginx

nginx-proxy

 

 

添加Nginx为系统服务

Nginx安装完成后默认不会注册为系统服务,所以需要手工添加系统服务脚本,为大家提供一个我写好的并测试通过了的Nginx的服务脚本,直接复制,并放到/etc/init.d/下更名为nginx并更改权限chmod +x /etc/init.d/nginx即可.

启动nginx

service nginx start

或者

/etc/init.d/nginx start

其他命令直接看脚本就可以,很简单。

#! /bin/sh
#用来将Nginx注册为系统服务的脚本
#Author CplusHua
#http://www.219.me
#chkconfig: - 85 15
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Nginx Daemon"
NAME=nginx
DAEMON=/usr/local/nginx/sbin/$NAME
SCRIPTNAME=/etc/init.d/$NAME
#守护进程不存在就退出
test -x $DAEMON ||exit 0
d_start(){
	$DAEMON ||echo -n "aready running"
}
d_stop(){
	$DAEMON -s quit || echo -n "not running"
}
d_reload(){
	$DAEMON -s reload || echo -n "could not reload"
}
case "$1" in
	start)
		echo -n "Starting $DESC: $NAME"
		d_start
		echo "."
	;;
	stop)
		echo -n "Stopping $DESC: $NAME"
		d_stop
		echo "."
	;;
	reload)
		echo -n "Reloading $DESC: configurationg....."
		d_reload
		echo "reloaded."
	;;
	restart)
		echo -n "Restarting $DESC: $NAME"
		d_stop
		sleep 3
		d_start
		echo "."
	;;
	*)
		echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
		exit 3
	;;
esac

exit 0

注意: #chkconfig: – 85 15 这一行-和85之间必须要有空格,否则可能无法使用chkconfig来配置开机启动