应用移植指南
一,为什么要移植应用
SAE禁止IO写操作,代码目录不能写入。这意味着普通程序的上传图片、生成缓存等操作都不能在SAE上正常运行,这时候你需要对这些代码进行修改后才能让你的程序运行在SAE上。
SAE为什么要禁止IO写操作?
SAE采用分布式架构设计, 应用代码将部署在多台前端服务器上, 每次访问请求可能到达不同服务器。(如下图):
假设现在有A、B、C、D四台服务器。用户上传一张图片到A服务器,第二次访问请求可能到达B服务器,此时将无法获取保存在A服务器上的图片。
SAE使用MemcacheX、Storage等存储型服务代替传统IO操作,效率比传统IO读写操作高,有效解决因IO瓶颈导致程序性能低下的问题。
另外,很多网站被攻击都是因为服务器有写的权限,程序代码能被黑客修改,SAE禁止写操作,也提升了服务器的安全性。
所以SAE为了提升性能和安全,禁止本地IO写操作。开发者可以使用Storage,Memcache,KVDB等服务存储需写入的数据。
二,快速移植你的程序
使用Wrappers
SAE虽然禁止了IO写操作,但是并没有禁止fwrite,file_put_contents等写操作函数,同时SAE还提供了Wrappers服务,这使得移植程序也比较简单。 假设我们要将下面的代码移植到SAE上。
file_put_contents('test.php','');
include 'test.php';
?>
只需要给文件地址加上前缀就可以了
file_put_contents('saemc://test.php','');
include 'saemc://test.php';
?>
如果地址的前缀为saemc:// 表示在Memcache中进行读写操作 ,如果前缀为saestor:// 表示在Storage中进行读写操作。前缀为saekv://就是对KVDB的操作。这就是Wrappers的功能。
注意:
1,在使用Wappers前,需要先初始化相应的服务。
初始化Memcache:进入Memcache服务管理后台 http://sae.sina.com.cn/?m=mcmng ,然后在网页右上角“我的应用中”选择指定应用。点击“点此初始化MC”的按钮就可初始化Memcache。
初始化Storage:进入Storage服务管理后台http://sae.sina.com.cn/?m=storage ,选择指定应用后 ,“点击创建一个domain”按钮进行创建。这里允许创建多个domain, 开发者使用Wrappers将文件上传到哪个domain,取决于文件地址的第一个目录名称。 如 “saestor://upload/image/1.jpg” 这样的地址,会将文件保存在名为upload的domain中。
另外Mysql和KVDB也是需要先初始化才能使用,如果程序有用到这些服务,请先初始化。
2,操作频繁的缓存不适合存储在Storage中。
Storage读写效率比KVDB和Memcache低很多。操作频繁的缓存不适合存储在storage中,所以除操作用户上传的文件外,尽量不要使用saestor://。
尤其是一些程序代码片段的缓存。如上面的例子,如果使用如 include 'saestor://xxx' 的代码来实现会使得程序性能较低。
理解了Wrappers的用法后, 就可以开始移植程序了。
利用报错快速定位
开发者可以利用SAE的错误提示,快速的定位到程序需要修改的代码。
首先保证你的应用开启了错误提示。进入应用的“代码管理”后台http://sae.sina.com.cn/?m=vermng, 看看对应版本的“错误提示”是否开启(默认是开启的)。 还有检查一下程序有没有类似error_reporting(0)的代码,屏蔽了错误提示。如果有,请先将他们注释掉。
然后将程序上传到SAE。如果有不兼容的地方,错误提示会告诉你具体文件的具体行。
如果出现类似这样的提示:
SAE_Warning: file_put_contents(./xxx.php) [function.file-put-contents]: failed to open stream: Permission denied in xxx.php on line 2
说明程序正在进行IO写操作, 只需给地址加上Wrappers的前缀,就能实现兼容。
如果你的程序的封装性好,更改IO写操作的代码, 往往很简单。比如ThinkPHP定义了RUNTIME_PATH常量。所有IO写操作产生的文件都会存放在 RUNTIME_PATH常量指定的文件夹中, 移植ThinkPHP程序, 只需要更改RUNTIME_PATH常量,加上saemc:// 前缀就可以了。其实其他框架或封装性比较好的程序,也是如此,只需更改一行代码,就能兼容IO写操作。如果你是重新用ThinkPHP开发程序的话,建议 使用SAE版ThinkPHP。
注:使用Wrappers后,有些操作是无效的。 比如file_exists ,大家可以直接将这样的函数注释掉。
如果出现类似下面的提示:
SAE_Warning: mysql_connect() [function.mysql-connect]: this app is not authorised in xxx.php on line 2
说明程序正在使用Mysql数据库,这时候需要初始化Mysql,并导入数据库。你可以在初始化后点击“管理Mysql”按钮,使用PHPMyAdmin进行数据导入。 当你数据比较大时,可以用DeferredJob服务来导入。
导入数据库后,还要将原程序中数据库用户名、密码等更改为SAE的。 SAE的数据库用户名、密码、数据库名使用常量表示。可以在mysql服务管理处看到。SAE的Mysql数据库支持分布式,能连接两个数据库。如果你的原程序只支持单数据库操作,请连接主库域名。
当你的程序在SAE上没有出现错误提示了,你的程序已经初步能在SAE上面运行了。你还要检查一下一些细节的功能是否实现。比如上传图片功能等。建议将上传的图片或其他附件存放在Storage中。图片存储在Storage中后, 图片的访问地址也和以前不一样。你需要使用Storage的getUrl方法获得图片访问地址,如:
$s=new SaeStorage();
$url=$s->getUrl('domain','filepath');//获得图片地址,filepath为图片在storage中的路径
?>
接下来,开发者可以对程序进行进一步的优化,让程序达到更好的性能。
三,性能优化
我们提供了一些优化的建议。
1 IO操作产生的文件进行区分存储
(1)建议将模板编译缓存或其他程序代码片段的缓存放在Memcache中,坚决反对将模板编译缓存放在Storage中, 因为Storage的读写效率比Memcache低,将它们存入Storage会导致你程序运行较慢。
(2)将上传的图片或附件存储在Storage中。如果你的图片需要防盗链等功能, 你还可以在SAE的服务管理后台,通过设置domain的属性能轻松的实现防盗链。
(3)将一些固定缓存存入KVDB中。有一些缓存不适合存储在Memcache中, 因为Memcache中的缓存有可能会消失,比如Memcache空间不足时,最早存入Memcache中的缓存就会被删除。所以你存入到Memcache的缓存,在读取时必须需要判断缓存是否存在,如果不存在重新生成。但有一些缓存生成一次后一般都不会变了,在读取缓存的时候不用判断它是否存在。 这类缓存建议使用KVDB进行存储。
2 实现数据库的读写分离
SAE MySQL数据库主库可读写,从库只读。查询使用从库消耗的云豆更少,且响应更快,所以建议大家尽量实现主从分离。现在很多框架,程序都支持读写分离,只需简单配置即可。如果程序只支持单数据库 可以尝试在执行SQL时进行判断如果是Select则连从库。
3 多使用SAE提供的服务
SAE提供了很多高效的服务,建议程序能使用SAE服务的地方尽量使用SAE服务。比如程序有排行榜的功能, 可以使用Rank服务实现;验证码的功能, 可以使用SaeVCode服务;发送邮件的功能, 可以使用Mail服务等等。请大家查看各个服务相关的文档进行学习。
4 考虑使用原生接口
Wrappers固然方便简单, 但它的效率肯定不如原生的Memcache或Storage接口。如果你很在乎效率问题, 可以考虑使用原始接口实现移植。 使用原生接口实现移植的方法可参考:http://qing.weibo.com/1631767865/6142cd3933000cj9.html
四,常见问题
1 实现伪静态
SAE不支持.htaccess文件,但是可以通过AppConfig服务实现伪静态。
2 生成静态页面
有些程序有生成纯静态html的机制。大家可以使用KVDB存储html静态页面数据,由于SAE禁止IO写操作,不能实现真正的纯静态,我们可以用伪静态的方式到达同样的效果,下面举一个简单的例子。
假设程序在未移植之前通过以下代码生成html文件:
file_put_contents('html/index.html', 'htmlcontent');
?>
这样用户通过浏览器输入地址 http://你的域名/html/index.html 访问到的是一个纯静态页面。
现在我们要将程序移植到SAE上。
首先将html数据保存到KVDB上。
file_put_contents('saekv://html/index.html', 'htmlcontent');
?>
使用config.yaml, 写一条伪静态语句
- rewrite: if (path ~ "/html/(.*)") goto "/readhtml.php?path=html/$1"
如果用户访问了html目录会伪静态到readhtml.php文件进行读取静态数据。
readhtml.php的代码为:
echo file_get_contents('saekv://'.$_GET['path']);
?>
这样,在SAE上用户也能通过浏览器输入地址 http://你的域名/html/index.html 访问到数据。
3 日志记录。
有些程序有日志记录功能, 如果日志读写太频繁,不适合将日志文件存入storage中,建议使用sae_debug实现日志记录。 但是sae_debug记录日志的同时也会向浏览器输出日志内容。很多程序希望能现实暗地记录日志, 大家可以通过封装函数实现。
如:
function sae_log($msg){
sae_set_display_errors(false);//关闭信息输出
sae_debug($msg);//记录日志
sae_set_display_errors(true);//记录日志后再打开信息输出,否则会阻止正常的错误信息的显示
}
?>
通过sae_debug函数记录的日志可以在应用管理后台中的“日志中心”查看,它属于debug类型的日志, 大家需要在搜索框中下拉菜单中选择debug类型进行查看。
4 缓存共享问题
SAE每一个应用能创建多个版本,但是这多个版本共用同一个Memcache,KVDB等 服务,有时候容易出现缓存共享问题。比如一个应用创建了两个版本,放有相同的程序, 程序有模版缓存机制,可能会出现,只修改了版本1的模板,却发现版本2的内容也被修改了。我们要避免不同版本之间缓存名称相同的现象。开发者可以使 用$_SERVER['HTTP_APPVERSION']变量给缓存名称加上应用的版本号
5 Memcache缓存需要有更新机制
Memcache缓存因为有消失的可能, 所以在读取Memcache缓存时应该要判断缓存是否存在,如果不存在重新生成缓存,否则的Memcache缓存一旦被删除而程序又没有更新缓存的机制,将可能导致网站不能正常访问。开发者可以在程序移植完成后在应用的Memcahe服务管理后台手动清空Memcache缓存,再测试一下网站是否能正常运行。 建议将不需要更新机制的缓存使用KVDB存储。
6 如何获得Storage的域名
有时候程序的图片访问路径可以定义前缀, 我们只需要将前缀替换为Storage的域名就可以了。 获得Storage域名的方法:
$s=new SaeStorage();
$domain=rtrim($s->getUrl('domain',''),'/');//注意getUrl的第二个参数为空
?>
7 有些地方不能用Wrappers
并不是所有文件地址前加上Wrappers相应的前缀都能实现兼容。 比如以下代码:
$img=imagecreatefrompng("http://sae.sina.com.cn/static/image/logo.beta.new.png");
//…经过了一些列的图片处理函数处理…
imagepng($img,'saestor://upload/logo.png');//想通过Wrappers保存处理后的图片
?>
上面的代码是不能将图片保存到storage中的。
开发者可以使用临时文件解决上面的问题。
$img=imagecreatefrompng("http://sae.sina.com.cn/static/image/logo.beta.new.png");
//…经过了一些列的图片处理函数处理…
imagepng($img,SAE_TMP_PATH.'logo.png');//保存为临时文件
file_put_contents('saestor://upload/logo.png', file_get_contents(SAE_TMP_PATH.'logo.png'));
?>
所以要注意,虽然大家把程序中文件地址加上了wrappers的前缀,也要检查一下 文件地址是否在用在了不支持Wrappers的函数上。
一般的文件操作函数都是支持Wrappers的,如file_put_contents,fwrite,file_get_contents,include,file_exists, filemtime,move_uploaded_file等等。 只有个别带特殊功能的函数不支持Wrappers。
8 SAE禁用了一些函数和类
出于平台安全性考虑,SAE禁用了一些函数了类,详情查看
http://sae.sina.com.cn/?m=devcenter&catId=220
请使用功能相同的其他函数代替禁用的函数,如可用SimpleXML代替DoMDocument实现XML解析。
五,提交到应用仓库
开发者可以将移植好的程序提交到SAE的应用仓库, 这样别人可以通过应用仓库一键安装就能快速获得你的程序。
建议大家在移植程序的时候写一篇“移植记录”。提交应用时一并将移植记录提交给我们。这样方便我们审核你的应用。
移植记录需要写清楚移植程序时哪些地方做了修改,使用了什么SAE服务等。
提交到应用仓库的更多细节请见 http://sae.sina.com.cn/?m=devcenter&catId=230
或直接访问以下地址:http://sae.sina.com.cn/?m=apps&a=step_sae_app