RSS
 

流行PHP框架整理

20 十二

图虫之前是用Zend Framework开发的,全面用 Zend Framework重构那还是2008年的事情,期间一路跟着ZendFramework升级版本,从1.5一路跟到1.9,但是由于Zend Framework 2.0的差异太大,所以没有迁移到2.0。

转眼6年过去了,PHP世界发生了翻天覆地的变化,PHP 5.3以后引入的命名空间和trait和函数闭包等新特性,都彻底改变了框架的设计思路。PHP-FIG提出的PSR-0,PSR-4的策略,以及Packagist带来的包管理机制,极大地提升了PHP社区的活力。

新的PHP框架如雨后春笋般冒出来,尤其是Laravel这个号称给web艺术家设计的框架,简单看了几眼sample code,ORM的设计和我自己写的MyPDO如出一辙,大量的使用静态方法,避免不必要的对象实例化,它的代码风格简直深得我心。

但是Laravel和ZendFramework、django、rails一样,都是大而全的框架,框架内互相耦合了大量组件。对于一些轻量的API项目,其实我们根本用不着那些复杂的功能。于是,又有很多类似于express、web.py、flask、bottle的微框架应运而生。

到底用什么框架呢?简单整理对比一下几个流行框架:

 

1. 微框架——把文件層先脫離出來就是大一步了

Slim, microMVC, flight, Silex等,基本只做路由绑定的工作,其他功能一概没有。

Slim相对比较流行,flight和Silex也还不错。这类项目的开发一般不很活跃,因为实在没什么事情可以做。

这类微框架适合做一些功能简单的小项目,代码量少,能够达到不错的性能。

 

2. 功能齊全大庫系——把輪子通通拿來給本大爺用

Yii, CI, Cake, ThinkPHP,早期框架基本都属于这一类,在没有包管理的时代,引入独立组件是一个很麻烦的事情,所以这些框架一股脑把路由、视图、ORM、Acl、Pagination、Log等等统统自己做了一遍。

 

3. 安裝擴展系——不能高級一點嗎?

Laravel, ZF, Symfony,使用了大量PHP的高级特性。能体验到动态语言的强大魅力。

 

4. 用C写的PHP扩展系——速度最實際

Yaf, Phalcon

Phalcon 由于是一帮老外写的,开发者众多,社区完善,因此功能比较完善,各方面支持比较好。

Yaf毕竟是鸟哥一人在维护,而且鸟哥也太忙了,Yaf功能有限是必然的。

Phalcon/Yaf 适合做对性能要求很高的API项目。

 

参考链接

http://shen2.cn/question/19558755/answer/24228194

 
 

终于解决了mysql参数thread_concurrency的设置问题

20

已经在一个非常奇怪的数据库问题上卡了很久,slow log里面全是一些非常基本的sql语句,主键查询或者根据主键更新简单字段,本来应该是毫秒级返回结果的sql,居然总是超时。innodb分明是行级锁,本来这些单行操作是innodb的优势项目,应该毫无压力的,居然成为了瓶颈。

反复调整参数,并且请教了专家之后仍然没有很好地解决,之前增加了

innodb_purge_threads = 32 # 5.6之后才支持大于1, 5.5上会自动变成1

让每隔10秒的purge操作开独立的进程有一定的改善,但是仍然还是有很多阻塞的情况和很多slow log。

今天在安装一台新mysql的时候看到这样一段错误消息

[Warning] option 'thread_concurrency': unsigned value 0 adjusted to 1

我非常惊讶,因为我一直以为thread_concurrency=0的意思是不设置thread_concurrency,即无限。如果thread_concurrency=1,那就意味着mysql始终只能有一个并发thread,这显然会造成阻塞,严重影响性能。

把这个参数改成16(cpu总线程数)之后,这个阻塞的问题彻底解决了。在top里经常能看到mysqlCPU占用率超过200%以上的瞬间,而原来mysql很少能超过200%。slow log里面也不再出现那些简单查询的日志了。

查了一下相关信息,众说纷纭,有很多人包括官方文档说这个参数没有意义,仅仅针对solaris才有效。

percona的博客上有人写了一篇文章说thread_concurrency不是你想的那样,修改这个参数是浪费时间。我谨慎表示认同。
http://shen2.cn/2012/06/04/thread_concurrency-doesnt-do-what-you-expect/

并且还说这个参数在5.6.1之后会被废弃。

还有一些中文文章也认为这个参数没有意义
http://shen2.cn/uid-167175-id-3484871.html

至少经过我实践,这个参数在linux下面是有效的。默认是10,我改成0并被系统强制变成1之后,造成了经常阻塞的问题。目前我设置的是16,等于CPU线程数。

我为什么会蛋疼地以为把这个参数改成0会有效呢,大概是因为受了innodb_thread_concurrency的影响,innodb_thread_concurrency是可以并且推荐改成0的。

在我看来这个参数似乎除了坑人之外真的没有什么别的作用了,默认thread_concurrency=10就已经足够可用了,确实不需要修改。早一点升级到5.6告别这个参数吧。

 
 

ubuntu 13.10的源中的php5 需要单独安装php5-json

20

一直用ubuntu的源里的php5,并且由于一直要用到php5的最新特性,一直在追新版。

升级了13.10的源之后,php升级到了5.5.0,发现多出来一个php5-json,这是两年前就已经消失的。php5.3以后,json扩展一直是默认就装上的,怎么又冒出来一个独立的?

测试了之后发现,默认安装的php5.5.0里面没有json_encode函数,也没有json扩展。看来这次又把php5-json这个扩展独立出来了。估计是想允许人们修改这个json功能实现更高性能的json_encode()和json_decode()。

这在升级php5.4到php5.5的时候是一个坑,记在这里。

 
 

locale: Cannot set LC_ALL to default locale: No such file or directory

18

装ruby的时候出错:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = "en_US:en",
LC_ALL = (unset),
LC_PAPER = "zh_CN.UTF-8",
LC_ADDRESS = "zh_CN.UTF-8",
LC_MONETARY = "zh_CN.UTF-8",
LC_NUMERIC = "zh_CN.UTF-8",
LC_TELEPHONE = "zh_CN.UTF-8",
LC_IDENTIFICATION = "zh_CN.UTF-8",
LC_MEASUREMENT = "zh_CN.UTF-8",
LC_TIME = "zh_CN.UTF-8",
LC_NAME = "zh_CN.UTF-8",
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_ALL to default locale: No such file or directory

网上普遍的解决方法都是:修改/etc/default/locale,增加:

LC_ALL="C"

确实能解决这个问题,但是似乎我有一台不出错的服务器上,并没有设置LC_ALL。强制设置LC_ALL有点粗暴,一定有更好的解决方法。

研究了一下,最佳方法是,修改/var/lib/locales/supported.d/local,追加一行:

zh_CN.UTF-8 UTF-8

然后:

sudo locale-gen
sudo dpkg-reconfigure locales

就完美解决了。

 
 

php_value和php_admin_value的区别

13

调试的时候发现无论如何都看不到出错信息,而我确实已经设置了ini_set(‘display_errors’, 1),检查之后发现原来是我在php-fpm的pool的conf中,设置了php_admin_value[error_reporting] = 2039

php_admin_value到底和php_value有什么区别,我原来以为是某些重要的,初始参数需要php_admin_value,动态参数需要php_value。

实际上不是,php_admin_value代表这个设置不能在php程序里被ini_set()函数所覆盖,详情见:

http://shen2.cn/manual/en/configuration.changes.php

 
 

nosql数据库选型

10

今天在书店里翻完了一遍《七天七数据库》。这本书简单介绍了postgreSQL,riak,mongodb,HBase,riak,Neo4j,redis七个数据,并着重谈了数据库的特性差异和在部署维护时候的特点,并对不同需求下的数据库选型做了很多建议,感觉受益非浅。

我的几个项目,都遇到了mysql 向nosql过渡的问题,应该如何选型,我终于有了初步的方案。

社区网站的关系数据:neo4j

原来大量使用关联表的方式来存储,schema怎么看都觉得恶心,一共只有三列,两列是双重主键。现在有了对neo4j这样的图数据库,天生就是为了解决这样的问题而生的。原来网站里,人对小站的关注关系,图片和相册的关系,图博和标签的关系,这些现在都可以用neo4j来存储。不光是简单存储关系,还可以存储关系的hash信息,几乎1:1直接还原了设计思想。neo4j现在主要的问题是分布式能力不足,虽说官方宣称可以存储上百亿的关系,但是整个系统里留这么一个单点,总是让人不放心。好在这个社区网站的规模还远远没有大到上亿的级别,neo4j足以应付。并且用neo4j可以在编程模式上有很大的帮助,性能上也有很大提升。

社区网站的内容数据:mongodb

社区网站有用户、站点、相册、图片、博客等模型,这些模型都有丰富的元数据,其中不乏很多字段会出现空值,原来用mysql,会造成空间浪费,但是如果用nosql就可以避免空间浪费。这些模型大多数情况都是主键查询,nosql能够发挥很大的性能优势。目前的规模并不大,对性能没有特别的要求,但是由于业务逻辑非常复杂,经常会出现复杂查询,cassandra和riak对索引虽然有支持,但是非常非常有限,完全不能满足业务的需要。mongodb对索引的支持非常好,对各种查询条件的支持几乎能兼容mysql绝大多数的功能。我们希望能够简单快速地实现复杂查询,满足业务快速迭代的需要。因此,mongodb最适合最为社区主要模型的存储数据库。

原来的redis主要就是用来缓存常用模型的,而mongodb其实也有内存缓存,之前有过相关的测试,证明如果mongodb能够载入所有的数据到内存中,性能和redis相差无几。如果使用mongodb,那么redis这一层其实基本上是多余的。那么我们就只需要mongodb+neo4j就能完整实现整个应用了。

微博数据的本地缓存:cassandra

本来我考虑是用mongodb,因为mongo的数据类型是JSON,和微博的返回结果完全一致,可以在不考虑任何数据结构的情况下,将查询结果直接存进mongodb。但是mongodb有两个比较大的问题,一是他是强一致性的,而实际上我们对一致性的要求并不高,甚至希望用弱一致性(W=0,R=1)来保证高可用;二是他的写性能并不如cassandra,由于cassandra采用了多层SSTable的方式,使得它能够在多次对同一个内容进行写操作时,merge多个SSTable成一个SSTable,即使反复update同一份数据也不会降低性能,非常适合SSD。

这个业务的特点是,写比读还多,并且同一份数据经常反复写。所以看来还是cassandra更加合适一点。

高并发api接口服务数据库:cassandra/riak

需求是读取和写入的并发都非常大,每天动态访问量上亿,尤其是读取。排除HBase,因为太笨重,排除mongodb,因为它仍然是主从结构,我非常不喜欢投票选主的模式,数据分片方面支持有限。其实可选择的只剩下riak和cassandra了。riak支持任意格式的数据,比较适合全手动地存储。cassandra是面向列的,能够帮助我们更多地完成一些业务逻辑。riak完整实现了向量时钟,而cassandra通过时间戳维护一致性。不过对cassandra和riak的索引机制还不够了解,无法确定索引的方便程度和可维护性。暂时还是偏向于cassandra。

 
 

拟物化和扁平化

01

我非常支持扁平化的趋势,准确地说,我认为目前的趋势是抽象化,扁平化只是抽象化的一种典型形式。

1. 拟物化的局限
所谓拟物,必须是现实世界中已经有的物体,而且是人们日常的生活中经常使用的物品。但遗憾的是,人们生活中使用过的东西是非常有限的,相机、指南针、时钟、收音机、录音机……我们每个人都熟识并且会使用的“设备”不超过100件,而且这仅仅是对于70后80后而言。对于00后出生人来说,他们从出生就没见过磁带录音机,拨盘电话,收音机,红白游戏机,BP机,大哥大等这些已经被淘汰的设备,我们有理由相信,未来我们的孩子,可能连鼠标、指南针、随身听都不会认识,因为这些设备都被一部手机所代替,甚至手机有一天也会被代替。
那么,当我们熟识的设备越来越少,而手机应用所要实现的功能越来越创新的时候,这个矛盾就出现了。应用的功能太创新,根本找不到一个现实生活中的物来拟。
所以,拟物的风格会限制住创新应用的发展。

2. 拟物的极限
iOS6之前的版本,其实已经把拟物推到了一个非常高的高度,视觉上每一处的纹理、阴影、质感,每一个细节都经过精雕细琢,堪称完美。这个时候想要有所超越,尤其是想要在拟物这条路上有所超越,已经非常困难。
同时,我们发现,市场上非常多相机应用都找一个相机来做拟物,音乐应用都找一个老式唱片机来拟物,所有的指南针应用打开都是一个指南针。拟物化带来高度的同质化。
更遗憾的是,由于指南针、唱片机、收音机这样的产品其实都是已经被淘汰的设备,而这些设备早已停止了创新停止了改进,是死的。但是应用是活的,要继续改进发展。假如沿着拟物化这条路走下去,10年20年50年之后,这些应用打开来还是老样子。你不觉得悲哀么?

3. 从拟物到抽象
其实我非常反对从拟物到扁平这种提法,我认为现在的趋势并不是扁平化,而是抽象化扁平只是抽象的一种视觉形式,抽象化其实有更多的可能性。
回顾历史,我们会发现从拟物到抽象是历史的必然,举文字的演变和绘画的发展作为例子:
几乎所有的文字一开始都是象形文字,用拟物的方式来描绘现实世界中的东西,但是随着人类社会的日趋复杂,越来越多抽象的概念涌现出来,人们发现无法用拟物的方式来表达,于是开始放弃拟物,采用表音的方式来记录语言。即使是汉字中,比重最大是形声字,纯粹的象形字也屈指可数。
类似的,绘画一直到摄影术发明之前都是在追求写实,极致的写实。但是摄影术发明之后,人们发现写实的绘画已经走到了尽头,已经无法再超越,唯一的方法就是另辟蹊径,用抽象的方式去绘画。于是当代的艺术,越来越抽象,彻底摆脱了现实世界的束缚。
纵观艺术史,我们都可以看出,一开始人们都努力去还原现实世界,在技法日趋完善的同时,人们开始意识到了“还原现实”的局限性,而开始冲破现实的束缚,走向抽象。
即使现在,仍然有相当多的普通人无法理解抽象艺术(有兴趣推荐大家去看一下MOMA艺术馆的藏品),但是已经没有哪个艺术家愿意再回到之前的艺术时代了。
类比手机的拟物化,我们有理由相信,在未来相当长的时间里,拟物化的视觉风格将仍然受到大多数普通用户的推崇,但是作为一个设计师,应该有这个高度看到抽象化的意义。

4. 拟物和极简的冲突
拟物就需要对物体的高度模拟,需要丰富的细节,于是我们需要质感、需要层次、需要阴影,这些最终都需要通过视觉元素来实现。但实际上用户最后需要关注的只是信息本身,这些视觉元素或许在用户使用初期,是一个赏心悦目的装饰,但是久而久之,对用户来说就是一种干扰信息,用户需要的是更简单更直接地得到他想要的信息。
再者说,接下来更多的随身设备,比如google glass,iWatch,都需要将交互过程进一步简化,如果继续坚持拟物化,很难想象在iWatch这个狭小的屏幕上,如何呈现一个细节丰富的物体。
所以说,拟物化其实和极简主义是背道而驰的。在形式追随功能的原则指导下,不得不放弃拟物,而实现功能最大化。

5. 扁平化 != iOS7
很多人因为不喜欢iOS7的视觉风格,而反对扁平化。这其实犯了一个明显的逻辑错误,iOS7只是在扁平化这个方向上做出了自己的尝试,只是一个早期版本。
实际上正在探索扁平化的,还有google,还有WP8,等等。不要把iOS7的不成熟看成是扁平化这个方向的错误。
现在我们所处的时期,正是拟物化的体系日趋完善,抽象化的体系刚刚建立的时期。拿一个初生的婴儿去和发育完全的成年人相比,显然是不公平的。

综上,我相信历史的车轮滚滚,抽象化的时代即将到来,纵使我们对拟物的时代有万般留恋,抽象化仍然不可避免。同时我们是幸运的,我们将会经历整个变革过程,我们是历史的亲历者。哦不,我们正在创造历史 !

 
No Comments

Posted in 创业

 

用unix socket加速php-fpm、mysql、redis的连接

22

图虫的服务器长期是单机运行。估计除了mysql之外,php-fpm和redis还可以在单机上共存很长时间。(多说服务器早就达成了单机每日2000万+动态请求,所以我对单机搞定图虫的大流量非常乐观)

如果是单机服务,其实就不需要用IP哪怕是127.0.0.1这样的IP去连接mysql/redis/php了,因为即使是127.0.0.1也是要走TCP/IP层的。

unix提供的unix socket来实现单机的端口访问,很多文章提到用unix socket可以提升连接速度。

我简单测试了一下,200次redis请求的耗时38ms,如果改成unix socket方式,立刻降到27ms。这简直是立竿见影啊,10ms的差距足以让我们有动力把IP方式改成unix socket方式。

Mysql(PDO)启用unix socket的方法
1.在PDO的DSN里面:原来写host:xxx,改成unix_socket:/var/run/mysqld/mysqld.sock (当然你可以在my.cnf里面设置成别的)
2.给mysql的用户名@localhost,设置访问权限。由于unix_socket并不是主机,所以用unix socket方式连接mysql,mysql会强制认为用户是来自于localhost,所以一定要给username@localhost设置权限,而不是username@’%’

redis(phpredis)启用unix socket的方法
1.redis 默认没有开启unix socket,需要在/etc/redis/redis.conf中修改。注意unixsocketperm 777

unixsocket /var/run/redis/redis.sock
unixsocketperm 777

2.用phpredis连接:

$redis->connect('/var/run/redis/redis.sock')

nginx + php-fpm启用unix socket的方法
1.php-fpm 的pool配置文件中:

listen = /var/run/php5-fpm.sock;

2.nginx sites的配置文件中:

fastcgi_pass unix:/var/run/php5-fpm.sock;

由于redis连接次数很多,因此redis使用unix socket的效果最明显,mysql其次,php基本上没有用不用sock都差不多

 
 

update语句中的子查询表达式导致锁表

22

mysql的压力已经越来越大了,时不时出现响应迟缓的问题。

查看slow log中有大量对主键进行查询然后更新的语句,rows examined等于1,竟然执行时间超过1秒。语句大概是这样样子的:

update table_a set comments = (select count(1) from table_b where id = table_a.id) where id = 123;

看来看去,唯一的可能性就是子查询导致锁住了table_b,网上查了一下,阿里巴巴的DBA博客提到过这个问题,是由于mysql对子查询的优化不够,导致锁表。

把这句话拆成两句之后,死锁问题得到了明显的改善。

虽然说把这句话拆成两句话,会牺牲一致性(从select count完成到update有时间差),但是为了保证高可用,对于这样非关键的计数字段,就不苛求了。

 
 

ubuntu 13.04以后使用add-apt-repository依赖software-properties-common

02

由于使用minimal方式安装服务器,所以各种基础包都没有。使用add-apt-repository添加ppa软件源的时候,提示common not found。

这个错误之前经历过,只要安装python-software-properties就可以了。可是这次竟然不行,搜索了一下发现是因为新版本的ubuntu改了依赖关系。现在需要:

sudo apt-get install software-properties-common

于是就可以使用add-apt-repository了。

 
 
第 1 页,共 34 页12345102030...最旧 »