之前公司有个SNS方向的项目,由于有过Elgg的经验,所以选定继续采用Elgg作为基础来进行二次开发。项目中也更深入了解了Elgg的原理和特性,在性能优化和分布式扩展上积累了一些经验,分享记录一下,希望对有兴趣的童鞋有所帮助。
1. Elgg是什么
简单来说,Elgg是一套开源的基于PHP开发的社交网络平台套件,最初接触到Elgg的时候是2008年国外InfoWorld组织的一个开源软件评选,Elgg被评为best open source social networking platform。Elgg实现了社交网络常见的基本功能:关注、好友、微博、信息流、日志、群组等等。Elgg最有特点的是它的插件结构,除了极少数核心功能以外,大部分功能都是通过插件的形式实现,也就意味着各个功能模块都可以被重载替换或者停用,很方便开发者分别对各个功能进行修改更新,而不影响其他模块的正常运行。
此外,Elgg本身对object metadata和attribute的实现形式在编程开发上提供了很大的简化,开发人员可以用类似NoSQL的赋值语法$object->anything = anything 添加和修改任意的metadata,而不用去考虑扩展数据库表的字段等问题。
当然,这些优点在某些程度上反而变成了Elgg的缺点,开发上的便利对性能会有一定的影响,这些我会在以后的文章里具体解释。
2. Elgg的分布式部署架构
Elgg本身是典型的LAMP架构,很明显,单节点部署的模式不能满足高可用、负载均衡等等已经不算很新的要求,于是有了下面这样简单的分布式部署架构:
最前端用HA实现负载均衡,接一系列可以水平扩展的Web Server运行Elgg程序,后面接一个共用的Database (MySQL)。为满足可用性要求,MySQL也需要配置Master/Slave结构。
LAMP结构的这类应用,压力瓶颈最容易集中在数据库一层,因此在单台数据库能够支撑之前,master/slave的结构够用,能保证服务稳定运行,如果压力进一步增大,则首先需要考虑实行读写分离,在应用中分别配置读数据库源和写数据库源(需要修改一定的代码),如果嫌麻烦,也可以使用mysql自带的一个mysql-proxy组件来实现读写分离,分散数据压力。如果数据量增长到更大的规模,则需要考虑进行分表了。当然,优化不是一步到位就可以搞定的,等到你必须要进行分表的时候,你的业务的访问量应该已经大到相当惊人的规模了:) 在那之前,倒不用过多考虑这样的问题,还是先想想怎么把业务做到那么大访问规模再说:)
3. Elgg+Nginx+Php-fpm
传统的LAMP架构中都是指的Apache服务器,对web服务器领域有所了解的同学一定都知道Nginx,是比apache更高效更灵活的选择,所以我们首先将web server这一层换成nginx,再接一个Php-fpm后台程序用来解析PHP代码。由于Elgg本身只提供了为apache准备的htaccess文件,需要编辑nginx的配置文件,下面给出一个elgg的nginx配置示例:
server {
listen 80; ## listen for ipv4
server_name localhost;
root /opt/web;
index index.php index.html index.htm;
access_log off;
error_log /var/log/nginx/elgg.error.log;
location ~* favicon.ico {
log_not_found off;
}
rewrite action/([A-Za-z0-9\_\-\/]+)$ /engine/handlers/action_handler.php?action=$1 last;
rewrite pg/([A-Za-z0-9\_\-]+)/(.*)$ /engine/handlers/page_handler.php?handler=$1&page=$2 last;
rewrite pg/([A-Za-z0-9\_\-]+)$ /engine/handlers/page_handler.php?handler=$1 last;
rewrite cache/(.*)$ /engine/handlers/cache_handler.php?request=$1 last;
rewrite services/api/([A-Za-z0-9\_\-]+)/(.*)$ /engine/handlers/service_handler.php?handler=$1&request=$2 last;
rewrite export\/([A-Za-z]+)\/([0-9]+)/?$ /engine/handlers/export_handler.php?view=$1&guid=$2 last;
rewrite export\/([A-Za-z]+)\/([0-9]+)/([A-Za-z]+)\/([A-Za-z0-9\_]+)/$ /engine/handlers/export_handler.php?view=$1&guid=$2&type=$3&idname=$4 last;
rewrite xml-rpc\.php /engine/handlers/xml-rpc_handler.php last;
rewrite mt/mt-xmlrpc\.cgi /engine/handlers/xml-rpc_handler.php last;
rewrite tag/(.+)/?$ /engine/handlers/page_handler.php?handler=search&page=$1 last;
rewrite rewrite\.php$ /install.php last;
if (!-e $request_filename){
rewrite ([A-Za-z0-9\_\-]+)/(.*)$ /engine/handlers/page_handler.php?handler=$1&page=$2 last;
rewrite ([A-Za-z0-9\_\-]+)$ /engine/handlers/page_handler.php?handler=$1 last;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
client_max_body_size 200m;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
fastcgi_buffer_size 1024k;
fastcgi_buffers 32 1024k;
fastcgi_busy_buffers_size 2048k;
fastcgi_temp_file_write_size 2048k;
}
location ~* \.(css|js) {
expires 30d;
}
location ~* \.(bmp|ico|gif|jpg|jpeg|png)$
{
expires 30d;
}
}
这里有些细节说明一下:上面这个配置 php-fpm在本地的9000端口上提供服务,如果需要的话,可以配置一组php-fpm的upstream server, 然后配置nginx使用这一组服务器,真正做到水平横向扩展。此外,nginx本身有缓存静态文件的能力,对css,js和图像等静态内容,设置了缓存和失效时间,提高访问效率。
以上是在架构和配置上对Elgg进行扩展的基本介绍,后续我会深入Elgg的代码,从数据库访问、ache缓存、引擎启动优化等等各个方面解释对我们对Elgg进行的改造和优化,还有一些自己对这个架构的思考。