一些wordpress插件兼容php7.x后的一些修改

不知算不算手贱,把VPS服务器上的php升级到7.0, 虽然7.x与之前的兼容性是很高的,但移除了一大堆过时用法,而某些老应用仍然在使用。对个人wordpress站点里出现的错误,修正记录如下。全部是插件,wordpress官方程序,是没有问题的。

mysql_escape_string() 函数改为addslashes()

wp-thread-comment插件 wp-content/plugins/wordpress-thread-comment/wp-thread-comment.php  有多处

mysql_* 系列函数在php7里全部移除了,所以建议在所有文件里搜索一下 mysql_query, mysql_escape_, mysql_real_eacape 等函数,如:  grep -r mysql_query /path/to/your/site

split()函数改为explode()

auto-save-image插件 wp-content/plugins/auto-save-image/auto-save-image.php  122行

语法兼容

Configure SMTP插件  wp-content/plugins/configure-smtp/configure-smtp.php  171行,为函数定义添加默认值

public function options_page_description( $localized_heading_text = '' ) {

php下数据库持久连接,及apache模块下“数据库并发连接数超限”的潜在风险

php下的多个数据库引擎都提供持久连接的特性,实现了“连接池”的作用,让数据库连接“复用”,目的是减少php引擎连接数据库的消耗。这有类似fastCGI协议的设计初衷:让后端进程复用,节省启动关闭CGI进程的性能开锁。

数据库持久连接的实现方式

这需要从php的运行模式说起。典型的php运行模式是传统CGI、fastCGI、web模块三种。

其中CGI模式不支持持久连接,因为php每次处理请求,都是由一个独立的进程(操作系统的进程)处理,请求处理完毕,进程就销毁了,相应的数据连接之类的资源当然也已不存在,所以CGI本身是不支持持久连接的。

fastCGI模式下,php进程由进程管理器所管理。(apache下实现实例,参看这里)。不管哪种fastCGI方案,其背后都是一系列长期运行的进程(操作系统下的进程),进程本身可以保持资源,因此,php脚本引擎可以提供应用的接口,允许程序员将数据库连接保持下来,供下次php处理请求,可以直接复用这个连接。

web模块下,类似fastCGI模式。linux下apache默认prefork下,每个httpd进程在同一时刻只响应一个http请求,每个httpd进程可以看做一个fastCGI进程。

多数据库账号的持久连接

假设一web服务器下的所有应用,都是持久连接,并且使用了惟一的数据库连接账号。假设共开了10个fastCGI进程在运行,每个进程都保持了一个持久连接,如果当前处理请求需要连接数据库,直接使用该持久连接即可,不需要新连接数据库。事实上,运行一段时间后,就是这样状态。

假设该web服务器下的应用,共有10个数据库连接账号。每fastCGI进程,从启动开始,每处理一个新的数据库账号相关的请求,就要多保持一个持久连接。因为不同数据库账号的连接,肯定不能复用的。这样,在运行一段时间后,每个fastCGI进程都要维持10个持久连接,分别对应每个数据库账号。

以apache模块模式下运行的httpd进程,可以等同于一个fastCGI进程,上面讨论同样适用。

进程数及连接数讨论,及apache下的潜在风险!

如果web服务器下的的php应用,分别使用了多个数据库账号,而且全部连到同一台数据库服务器。这样,

该数据库的并发连接数 = fastCGI进程数 * 数据库账号数
如果php在apache模块下运行,使用httpd进程数代替fastCGI进程数

通常,fastCGI进程数量是比较有限的,对于一台web服务器,它接受的请求里,大多数请求都是静态的(想像一下,一个页面里,通常只有主html文档是动态,而里面的js,css,图片等等元素都是静态;这里不考虑“静态内容全部移到CDN上”的极端情况)。fastCGI进程数数,通常会远比http并发数小。

在apache模块运行的php下,所有请求都是由httpd进程处理的,每个httpd进程都有可能维护每个数据库用户相关的持久连接,如果数据库用户量较大,这个对mysql服务器并发的连接数影响非常大。通常mysql服务器都会设置一个最大并发数据,超过限制后,就不再受新连接!

php下持久连接的更多信息,参考官方文档 http://php.net/manual/zh/features.persistent-connections.php

 

CGI原理示例,及CGI,FastCGI,php-cgi,php-fpm等的总结

CGI

CGI全名“通用网关接口”(Common Gateway Interface),是一个技术规范,用来动态生成网页html。理论上可以使用任意语言写,只要支持标准输入输出及环境变量即可(标准输入输出概念参考C语言中stdio库的printf函数)。

举例简述一下实现细节,以类C语言伪代码演示(不想了解CGI细节可以跳过)

CGI程序 /usr/local/cgi/hello

printf("Content-type: text/html; charset=UTF-8")
printf("\r\n\r\n")
printf("hello world")

注意两个连续换行符号,它们是http头与内容的分隔。

假设web服务器,把对 http://localhost/hello的请求,转给 /usr/local/cgi/hello 处理,这就要启用一个进程支行hello程序,hello程序执行后标准输出结果如下

Content-type: text/html; charset=UTF-8

hello world

web服务器拿到结果,把并把hello程序的输出结果添加其它http头元素,如HTTP状态码、Connection: keep-alive等,这就是完整的http响应消息内容了,把它们一并发回给浏览器,一次CGI的http请求就完成。

这是个最简单的示例,我们忽略了http请求数据、本地目录文件等,事实上的程序会复杂得多。

通常是这样的,一个cgi-bin目录里,放置CGI可执行程序(类比上面的hello程序),web服务器通常不是把所有请求都通过CGI来处理的,而是把符合一定规则(比如url路径以.pl结尾)的请求,启动CGI进程,并将对应的web目录文件(比如hello.pl)传给CGI程序,CGI程序按hello.pl文件的内容执行,标准输出结果再由web服务器拿到并补充http头等,生成http影响数据,发回给浏览器。

这里的CGI程序的行为,与脚本语言解释器类似(本地目录的相关文件当脚本程序,被CGI程序解释执行)

CGI的具体细节参考rfc3875,或 英文维基CGI词条

FastCGI

传统的CGI程序,对每次http请求,都要启动一个操作系统层面的进程process,进程处理一次就结束。下次http请求还得再起动。启动进程对于操作系统来说是较耗费时间的操作,所以在CGI的负载能力比较有限,在启动关闭进程上浪费严重性能。

针对这一点,FastCGI协议被出了:让CGI进程长期驻守,有请求,就直接给它处理,没有就等待。

可以这样认为,FastCGI是CGI的改进版,虽然并不完全兼容。传统的CGI要改造成FastCGI,很多代码可以直接借用的。

因为CGI/FastCGI协议都是语言无关的,只要能按这个规范来,任何语言都可以。所以有很多具体的技术支持,比如php的CGI/FastCGI模式运行;这点后面讨论。

单个FastCGI进程的负载是有限的,所以通常需要多个进程同时工作,这就可以同时接受更多请求,提高并发数。

如果某个进程运行时间长了,占用了过多内存,或者该进程僵死了,需要结束它,并启动新进程;或者想在并发量大时,自动增加FastCGI进程数,而并发小时,自动减少;...这些就需要有有“人”来管理,就是FastCGI进程管理员的工作了。

php-cgi

编译后php的二进制文件里,在bin目录里有php-cgi文件(在windows版里是,php-cgi.exe),即是支持CGI/FastCGI的可执行程序。

可以这样执行一个php文件  /path/to/php-cgi /path/to/your-php-file.php

php-fpm

前面说过,FastCGI程序是驻守系统进程中的,该进程不可能凭空启动,那这个进程由谁管理呢?这就是FastCGI进程管理员 (FastCGI Process Manager)。对于PHP而言,在php 5.3以后的版本,自带的php-fpm即是php的fpm。(php 5.2及以前版本,可以通过补丁的形式将php-fpm整合到php中,或使用其它方案)。

不过,支持php的fpm并非只有php-fpm,还有其它方案,只要起到管理fastCGI进程的启动、关闭等 功能即可。apache下的mod_fcgid即是另一个可选方案。所以,在apache下,如果使用mod_fcgid整合php,就不需要php-fpm了。有更广泛支持的Spawn-FCGI是另一个备选项。

 

 

mac port 更新报错:Error installing new MacPorts base: command execution failed

核心提示:

回想你是不是更新过xcode,而且更新过后,还没有使用过。如果是,请同意一下命令行版的用户协议,终端里运行

sudo xcodebuild -license

然后按提示输入 agree,完了重试port更新。

如果不是这样,那请转到google搜索,并啃英文资料吧。

其实只需要看到这里就够了,下面是发现这一点的过程,可以认为是废话,不推荐继续阅读;读了也不多,多花费一点时间而已。

继续阅读

生产环境下MySQL服务配置优化参考样本/CentOS 6.x MySQL 5.1.73

这里有mysql配置文件,分别是实体机生产环境下与vps下的两个版本;后面有二进制日志相关的配置。

注意事项:如果修改了innodb_*参数,尤其是修改了innodb_log_file_size ,启动前要删除/var/lib/mysql/ib_logfile{0,1}两个文件,启动后一定要检查一下mysql日志,是否有相关错误或警告消息。

环境 CentOS 6.x 自带的MySQL 5.1.73

在原始配置文件  /etc/my.cnf 基础上,在 [mysqld] 节内增加配置参数。实际应用中,请按硬件及负载酌情修改。

#add by feng 120418  --------------------------
#skip-locking
skip-name-resolve
skip-external-locking
key_buffer_size = 256M
#table_cache = 3072
table_open_cache = 3072
read_buffer_size = 2M
read_rnd_buffer_size = 2M
sort_buffer_size = 2M
myisam_sort_buffer_size = 256M
thread_cache_size = 8
query_cache_size= 512M
query_cache_limit= 5M
tmp_table_size=1024M
max_heap_table_size=3000M
max_allowed_packet = 16M
innodb_buffer_pool_size = 512M
innodb_log_file_size = 512M
innodb_additional_mem_pool_size=512M
innodb_log_buffer_size=64M
max_connections=2000
max_user_connections=800
join_buffer_size = 8M
open_files_limit = 65535
#tmpdir=/dev/shm
max_connect_errors=1000
#add by feng 120418  end ---------------------

1-2G内存的个人VPS下配置参考

因为开启了主从复制,会产生大量二进制日志占用磁盘空间。如不需要,可以删除复制相关行。

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

#add by fengyqf start
skip-name-resolve

innodb_log_buffer_size=32M
innodb_buffer_pool_size=64M
innodb_log_file_size=16M
innodb_additional_mem_pool_size=16M

#replication safe for innodb engine
innodb_flush_logs_at_commit
innodb_support_xa=1


#replication
server-id=100
log-bin=mysql-bin
log-error=mysql-bin.err
expire_logs_days=30
sync_binlog=1
#add by fengyqf end

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

从服务器配置

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

skip-name-resolve

server-id=201
log-bin=mysql-bin
relay_log=/var/lib/mysql/mysql-relay-bin
log_slave_updates=1
read_only=1


[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

二进制日志的定期清理或手工清理

定时清理。通过参数 expire_logs_days 指定过期天数,过期自动清理;具体天数据按实际情况定(空间与同步延迟等)。该参数可运行时设定。

expire_logs_days = 10 

手工清理。root登录mysql客户端,执行purge命令。

> PURGE {MASTER | BINARY} LOGS TO 'log_name'
> PURGE {MASTER | BINARY} LOGS BEFORE 'date'

其中 log_name是show master logs; 显示的日志文件名,如 mysql-bin.000001. 应用举例:

> PURGE MASTER LOGS TO 'mysql-bin.000003';  //清除mysql-bin.000003(含)之前的日志
> PURGE MASTER LOGS BEFORE '2016-11-05 10:00:00';   //清除2016-11-05 10:00:00前的日志
> PURGE MASTER LOGS BEFORE DATE_SUB(NOW(),INTERVAL 3 DAY);
  //清除3天前日志,使用BEFORE函数计算日期,变量的date自变量还可以为'YYYY-MM-DD hh:mm:ss'格式。详查手册

清理二进制日志的影响。如果当前服务器有一个活跃的从属服务器,该从服务器当前正在读取您正在试图删除的日志之一,则本语句不会起作用,而是会失败,并伴随一个错误。不过,如果从属服务器是休止的,并且您碰巧清理了其想要读取的日志之一,则从属服务器启动后不能复制。当从属服务器正在复制时,本语句可以安全运行。您不需要停止它们。(参考

 

MySQL服务器设置max_user_connections防止连接耗尽,以提高可用性

问题简述/现象及原因

一台MySQL服务器上,有多个数据库,由不同用户使用,相互之间没有或很少关联性。典型的实例是虚拟主机,或者有N多个小网站的某些低频企业应用。

这种环境下,难免有部分应用的质量不高:

出现效率极低的慢查询 -> 后续请求大量被locked排队 -> MySQL服务实时连接数达到最大连接数限制  ->  无法建立新连接

so, 所有相关应用全部挂掉

应对方案

为防止上述情况发生,要为MySQL配置max_user_connections参数。该参数作用是设置单个用户最大连接数限制。具体设置多少,要根据实际情况再裁定。

需要引起注意的是,这个参数是针对所有用户的限制,所以要考察正常情况下连接数最多的用户。可以使用下面语句实时查询各用户连接数。

select `USER`,COUNT(`USER`) AS CNT from information_schema.PROCESSLIST GROUP BY `USER` ORDER BY CNT DESC;

一个参考数值,将 max_user_connections 设置为正常情况下单用户最大连接数的3-5倍。

max_user_connections参数可以在MySQL运行时动态设置 set global .... 当然,也要同步写到my.ini配置参数里。

方案评估

max_user_connections 是个一刀切的配置参数,好像MySQL不能对每个用户设置连接数,并发查询数,io,cpu占用或其它什么什么的细粒度参数。或许并非一定有效。

与max_connections参数对比

max_connections 是指整个mysql服务器的最大连接数;

max_user_connections 是指每个MySQL用户的最大连接数

MySQL官方文档相关章节