Archive for 十月, 2011

web server部署的是apache,同时还跑着memcached和cabinet server。

最近页面打开比较慢,经查看,web server 的cpu、load以及数据库服务器的cpu、load、memory都很正常。但是web server 8g的内存即将消耗尽。将memcached迁移走,页面响应明显变快。

————————————————————

另外,sar -B 看到,page faults达到每秒15000左右,但是page in 和page out都不高。page faults是包括Minor page fault和Major page fault的。If the page is loaded in memory at the time the fault is generated, but is not marked in the memory management unit as being loaded in memory, then it is called a minor or soft page fault.If the page is not loaded in memory at the time the fault is generated, then it is called a major or hard page fault.

缺页中断可分为主缺页中断(Major Page Fault)和次缺页中断(Minor Page Fault),要从磁盘读取数据而产生的中断是主缺页中断;数据已经被读入内存并被缓存起来,从内存缓存区中而不是直接从硬盘中读取数据而产生的中断是次缺页中断。

我的猜测是,既然page in和out都不高,说明硬盘与内存间的page交换不多?而大多数是从内存cache里读入到可用区域的中断?所以,这样的中断次数,是可以接受的?

———————————

[admin@v080049 ~]$ /usr/bin/time -v date
2011年 10月 31日 星期一 18:32:36 CST
Command being timed: “date”
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 0
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 225
Voluntary context switches: 1
Involuntary context switches: 1
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

经过查证,不管连结的的方式是经过 hosts 或是 IP 的模式,他都会对 DNS 做反查
mysqld 会尝试去反查 IP -> dns ,由于反查解析过慢,无法应付快速多量的查询

解决办法:
1、修改my.ini文件,在 [mysqld] 行下添加  –skip-name-resolve ,重新启动mysql服务
2、访问的主机授权时用IP,最好把该主机的IP及主机名写到/etc/hosts文件中

经过以上的设定及重新启动过后,直到现在还没有看到一个 unauthenticated user 的情况发生
近日还是会持续的观察 Mysql 的运作情况,如有问题将会持续的禀报及解决

我有两台cabinet服务器,master-master类型的,使用B+ tree。有两次服务器宕机之后,重新启动cabinet,发现数据丢失,即通过接口无法读取到数据,但是tcb文件还是很大。

在本地虚拟机上模拟时,kill关闭数据不会丢失,而kill -9则会丢失数据,经过多次惨痛的教训说明,cabinet不是那么稳定,一定要做好它宕机以后的恢复和应急准备。

锁的问题(非根本问题,不是很重要)

摘录一台服务器的cabinet.log如下:

2011-10-22T22:04:02+08:00       SYSTEM  --------- logging started [1561] --------
2011-10-22T22:04:02+08:00       SYSTEM  process ID configuration: path=/home/admin/apps/tokyo/data/ttserver.pid pid=1561
2011-10-22T22:04:02+08:00       SYSTEM  server configuration: host=192.168.80.49 port=19999
2011-10-22T22:04:02+08:00       SYSTEM  maximum connection: 1048575
2011-10-22T22:04:02+08:00       SYSTEM  opening the database: /home/admin/apps/tokyo/data/shorturl.tcb#lmemb=1024#nmemb=2048#bnum=10000000
2011-10-22T22:04:02+08:00       SYSTEM  update log configuration: path=/home/admin/apps/tokyo/data/ limit=134217728 async=0 sid=49
2011-10-22T22:04:02+08:00       SYSTEM  replication configuration: host=192.168.80.27 port=19999 ropts=0
2011-10-22T22:04:02+08:00       SYSTEM  service started: 1561
2011-10-22T22:04:02+08:00       SYSTEM  listening started
2011-10-22T22:24:35+08:00       SYSTEM  --------- logging started [1492] --------
2011-10-22T22:24:35+08:00       SYSTEM  process ID configuration: path=/home/admin/apps/tokyo/data/ttserver.pid pid=1492
2011-10-22T22:24:35+08:00       SYSTEM  server configuration: host=192.168.80.49 port=19999
2011-10-22T22:24:35+08:00       SYSTEM  maximum connection: 1048575
2011-10-22T22:24:35+08:00       SYSTEM  opening the database: /home/admin/apps/tokyo/data/shorturl.tcb#lmemb=1024#nmemb=2048#bnum=10000000
2011-10-22T22:24:35+08:00       SYSTEM  update log configuration: path=/home/admin/apps/tokyo/data/ limit=134217728 async=0 sid=49
2011-10-22T22:24:35+08:00       SYSTEM  replication configuration: host=192.168.80.27 port=19999 ropts=0
2011-10-22T22:24:35+08:00       SYSTEM  service started: 1492
2011-10-22T22:24:35+08:00       SYSTEM  listening started
2011-10-23T11:40:04+08:00       SYSTEM  --------- logging started [1476] --------
2011-10-23T11:40:04+08:00       SYSTEM  process ID configuration: path=/home/admin/apps/tokyo/data/ttserver.pid pid=1476
2011-10-23T11:40:04+08:00       SYSTEM  server configuration: host=192.168.80.49 port=19999
2011-10-23T11:40:04+08:00       SYSTEM  maximum connection: 1048575
2011-10-23T11:40:04+08:00       SYSTEM  opening the database: /home/admin/apps/tokyo/data/shorturl.tcb#lmemb=1024#nmemb=2048#bnum=10000000
2011-10-23T11:40:04+08:00       SYSTEM  update log configuration: path=/home/admin/apps/tokyo/data/ limit=134217728 async=0 sid=49
2011-10-23T11:40:04+08:00       SYSTEM  replication configuration: host=192.168.80.27 port=19999 ropts=0
2011-10-23T11:40:04+08:00       SYSTEM  service started: 1476
2011-10-23T11:40:04+08:00       SYSTEM  listening started

可以看到这里没有logging finish的字样。而正常的log应该如下:
2011-10-27T16:19:57+08:00       SYSTEM  --------- logging started [15223] --------
2011-10-27T16:19:57+08:00       SYSTEM  process ID configuration: path=/var/ttserver/ttserver.pid pid=15223
2011-10-27T16:19:57+08:00       SYSTEM  server configuration: host=127.0.0.1 port=19999
2011-10-27T16:19:57+08:00       SYSTEM  maximum connection: 1048575
2011-10-27T16:19:57+08:00       SYSTEM  opening the database: /var/ttserver/shorturl49.tcb#lmemb=1024#nmemb=2048#bnum=10000000
2011-10-27T16:19:57+08:00       SYSTEM  update log configuration: path=/var/ttserver/ limit=134217728 async=0 sid=1
2011-10-27T16:19:57+08:00       SYSTEM  service started: 15223
2011-10-27T16:19:57+08:00       SYSTEM  listening started
2011-10-27T17:14:26+08:00       SYSTEM  listening finished
2011-10-27T17:14:26+08:00       SYSTEM  closing the database
2011-10-27T17:14:43+08:00       SYSTEM  --------- logging started [16864] --------

猜测数据没有丢失,只是由于某些原因无法读取。

在虚拟机的故障中,cabinet.log中发现如下ERROR,这时我在尝试用tcrmgr list获取其中的数据(共3次),tcrmgr返回的错误是“error: 9999: miscellaneous error”。

2011-10-27T17:16:35+08:00       ERROR   do_iterinit: operation failed
2011-10-27T17:16:38+08:00       ERROR   do_iterinit: operation failed
2011-10-27T17:16:50+08:00       ERROR   do_iterinit: operation failed

过了几分钟之后,tcrmgr不再报错误,但是返回为空。而这时telnet上去stats可以看到total_items和curr_items都不为空。

以上的do_iterinit: operation failed,经过查看tokyocabinet-1.4.47/tcbdb.c中的tcbdbcurfirst函数,推测应该是由于无法获取到文件锁而导致的。因为之前的ttserver非正常退出,文件锁还未释放完全。通过lsof命令可以看到当前该tcb文件锁被ttserver进程持有。

二进制文件损坏问题

参考该文可知,cabinet在非常退出情况下,确实会丢失数据:

http://hi.baidu.com/ah__fu/blog/item/309462946d463415d31b7058.html

我的想法是,由于cabinet使用二进制作为文件存储格式,在B+ tree的情况下,每次获取,需要先tcbdbcurfirst,即找到第一条记录。如果在异常情况下,导致部分数据没有完成写入,从而使二进制的格式损坏,则无法获取文件中的数据了!虽然这个时候,文件还是很大。

可以看到,在空数据的情况下,初始生成的tcb文件就有41m,其中必然含有一些头信息。

(有空的时候,可以看看它的存储格式,是否有可以改进以有利于文件容错性的地方。)

我们使用的是master-master双机cabinet,当一台cabinet服务器故障之后,可以由另外一台进行恢复。

考虑到几种恢复方式:

  1. 直接从无故障的机器,cp tcb文件覆盖至有故障的机器。(抛弃:因为cp时 tcb文件可能还有不完整的写入)注意:这种方式可能导致丢失大量数据!!!!!
  2. 利用无故障机器的ulog,及tyrant提供的tcrmgr restore命令进行恢复。(抛弃:不太好确定ulog的时间戳,顾不好确定restore之后同步的基准时间戳;restore 1.4G的ulog,在8g内存、4核cpu、linux2.6的机器上,耗时2分钟)
  3. 每当本机有新的ulog生成时,将上一个ulog restore至备份的cabinet文件(可以本机,也可以其他机器);故障时,仅需要将备份cabinet文件覆盖,并restore最新的一个ulog即可。(抛弃:因为本机的ulog可能也是不完整的)
  4. 利用master-master架构,将故障机从集群里摘下,设置rts为0,从master里做完整的恢复(待确定时间)。

最终参考http://www.pin5i.com/showtopic-25438.html,做如下的恢复方式:

  • 从无故障机器tcrmgr copy -port 11211 masterhost ‘@/data/backup/backup.sh’  (如果tcrmgr copy命令中,参数以@开始,那么后面的字符串作为命令行执行;copy 1.2G的文件,1分钟之内完成)(copy的时候,masterhost可读,但不可写)
  • 将生成的备份文件 old-file-name.xxxx(xxxx为时间戳)scp至待恢复的机器,并改名为 old-file-name
  • 将xxxx时间戳写入到 待恢复机器的rts文件(作为replication time stamp的基准时间)
  • 启动待恢复机器的ttserver,使用该文件作为数据文件
  • 检查,copy之后的数据,应该已从无故障机器同步至待恢复机器了

附backup.sh:

#! /bin/sh
srcpath="$1"
destpath="$1.$2"
rm -f "$destpath"
cp -f "$srcpath" "$destpath"

最终实践中的备份方式,由于tcrmgr copy会对数据文件加锁,所以单独使用一台ttserver的机器做备份:

  • online的ttserver服务器可以有2台(A、B),备份的ttserver服务器2台(C、D)
  • 两台online的ttserver互为master-master,备份ttserverC以A服务器为master,D以B服务器为master
  • 每隔一段时间,比如6小时,在备份ttserver上,运行tokyo/tyrant/bin/tcrmgr copy -port 19999 192.168.80.27 ‘@/home/admin/apps/tokyo/tyrant/bin/backup.sh’ 进行全量备份;并删除几天前的旧备份文件
  • 一旦online server出问题,比如是A出问题,立刻将问题serverA以及对应的备份C摘下。以B、D建立online的ttserver。
  • 待A恢复完毕之后,以A、C作为备份机
    • 从C上scp一份最新的备份文件,并且以文件名中的时间,写入到A的rts文件中,作为同步的起始时间
    • 删除A上的ulog
    • 以该备份文件,覆盖A的数据文件,启动ttserver,以B为master,则备份文件之后的数据会从B同步到A
    • 以同样的方式,建立C和D之间的备份关系
cabinet的一些常见故障
  • 千万别kill -9,否则文件格式可能被损坏
  • 使用php的TokyoTyrant扩展连接cabinet,并且使用persistent方式时,如果之前已连接上,再关闭cabinet进程,则connect成功,但是get、set等操作都失败。使用非persistent时,可抛出异常:connect refused
  • 直接使用cp文件方式获取的B+tree数据文件,会导致:
    • 数据不完整
    • 若作为其他ttserver的master,会导致其他ttserver进程的崩溃

nginx采用默認安裝即可。

php with php-fpm patch

php需要先打上php-fpm的patch,以使之能生成php-fpm命令。参考:http://php-fpm.org/wiki/Documentation

php-fpm patch的下載地址為:http://php-fpm.org/downloads/,找到與使用的php版本一致的,diff文件也可以。

(我用的是5.2.5的php,在测试环境,patch是5.2的,结果make的时候就报错:undefined reference to `pestrndup’。去更高版本的php里程看看,是在Zend/zend_alloc.h中定义的宏,但是5.2.5中没有。)

(还是给我报错!郁闷了,想起来打patch的时候报了一堆fail,更换php为5.2.6版本,与线上一致,省得我处理完一个问题到线上遇到新的……)

cd /path/to/phpsrc; patch -p1 < /path/to/fpm.patch ( 注意,要找一个干净的版本,如果之前打过错误的patch!!)

./buildconf –force # 强制patch生效, 其实php-5.2.*是不需要这一步的;当前,php-5.3.*时需要,因为对应的patch是不稳定版本

config php的時候,需要注意,–with-apxs2代表Build shared Apache 2.0 Handler module,所以不要加上這個選項。

‘./configure’  ‘–prefix=/usr/local/phpcgi’ ‘–with-config-file-path=/usr/local/phpcgi/etc’ ‘–enable-fastcgi’ ‘–enable-force-cgi-redirect’  ‘–enable-fpm’ ‘–enable-dba’ ‘–with-db4′ ‘–enable-sockets’ ‘–with-curl’ ‘–enable-soap’ ‘–enable-ftp’ ‘–enable-libxml’ ‘–with-libxml-dir’ ‘–with-mcrypt’ ‘–with-zlib’ ‘–enable-pdo’ ‘–with-pdo-dblib’ ‘–with-mhash’ ‘–enable-bcmath’ ‘–with-openssl’ ‘–with-mysql=/usr/local/mysql’  –enable-mbstring –enable-zip –with-gd –with-jpeg-dir=/usr/lib/libjpeg.so –with-pdo-mysql=/usr/local/mysql/ –with-mysqli=/usr/local/mysql/bin/mysql_config

make ; sudo make install

这时会在安装目录下生成sbin/php-fpm和etc/php-fpm.conf。

继续配置php-fpm.conf,这里有static和apache-like两种pm模式。

php扩展

memcache

tokyo_tyrant

mslib

eaccelerator

记得每次安装完扩展之后,要重启或者reload php-fpm。

nginx的rewrite配制

由于默认的配置下,PHP无法获取到类似$_SERVER[PHP_SELF]之类的变量,需要include fastcgi.conf。

user  apache apache;
worker_processes  4;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
        use epoll;
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

        log_format  access  '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for';
    access_log  logs/access.log access;

    sendfile        on;
    #tcp_nopush     on;
        tcp_nodelay     on; 

    #keepalive_timeout  0;
    keepalive_timeout  65;

        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
        fastcgi_buffer_size 64k;
        fastcgi_buffers 4 64k;
        fastcgi_busy_buffers_size 128k;
        fastcgi_temp_file_write_size 128k;

        gzip on;
        gzip_min_length  1k;
        gzip_buffers     4 16k;
        gzip_http_version 1.0;
        gzip_comp_level 2;
        gzip_types    text/plain application/x-javascript text/css application/xml;
        gzip_vary on;

    server {
        listen       80;
        server_name  localhost;

                location ~ ^/status/ {
                        stub_status on; #Nginx 状态监控配置
                        access_log off;
                }
        }

        server {
                listen       80;
                server_name  test.try8.info;
                index index.html index.htm index.php;
                root  /ms/wwwroot/test/;

                location ~ .*\.(php)?$
                {
                        fastcgi_pass  127.0.0.1:9000;
                        fastcgi_index index.php;
                        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                }
        }

        server
        {
                listen       80;
                server_name  qq.try8.info sina.try8.info yoka.try8.info renren.try8.info;
                index index.html index.htm index.php;
                root  /ms/wwwroot/stry_v2/;

                location ~* .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires      30d; }
                location ~* .*\.(js|css)$ { expires      30d; }
                location ~* .*\.(html)$ {expires 1d;}

                rewrite ^/webroot/(.*)$  /app/webroot/$1 break;
                rewrite ^/(xfiles.*)/(.*)$  /app/$1/$2 break;
                rewrite ^/((?!index\.php|tryapp/TryAppManagement).*)$            /index.php/$1 break;

                location ~ .*\.php{
                        fastcgi_pass  127.0.0.1:9000;
                        fastcgi_index index.php;
                        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                        include fastcgi.conf;
                }
        }

        server {
                listen       80;
                server_name  itry.try8.info i.try8.info;
                index index.html index.htm index.php;
                root  /ms/wwwroot/happy_itry_v2/;

                location ~* .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires      30d; }
                location ~* .*\.(js|css)$ { expires      30d; }
                location ~* .*\.(html)$ {expires 1d;}

                rewrite "^/([^/]+)/admin(?:/(?:[-/_a-zA-Z0-9]+\.php)?)?$"  "/$1/admin/dispatch.php" break;
                rewrite ^/([^/]+)/[-/_a-zA-Z0-9]+\.php  /$1/dispatch.php    break;
                rewrite "^/([^/]+)/([^./]*)(?:/([^.?]*))?(?:\?(.*))?$"    "/$1/dispatch.php?control=$2&args=$3&$4&$query_string"  break;

                location ~ .*\.php{
                        fastcgi_pass  127.0.0.1:9000;
                        fastcgi_index index.php;
                        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                        include fastcgi.conf;
                }
        }

}

nginx 403 & 404错误

启动php-fpm和nginx,本地配置host访问,访问http://localhost/index.html是403错误,http://localhost/index.php是404错误。这些都是由于权限导致的。

index.html是由nginx直接产生的,index.php的错误则是由php-fpm导致的。

首先,需要保证代码所在目录、文件及其递归的父目录都是可以被nginx的user read的!其次,还要保证这些目录和文件也能够被php-fpm的user read!

然后,reload nginx和php-fpm即可。

性能测试与优化

nginx与apache的一个较大的区别是,它利用了linux2.6的epoll,而非之前的select或poll。这样就可以避免select模式下,轮询去查看是否有ready的端口,而是以事件驱动的方式去获取到ready的读写端口。

nginx一般不会配置成使用很多个worker_process,有人说配置为cpu核数*2。而每个worker_process可以同时处理的连接数目就是用workder_connections来配置的。由于采用了epoll的方式,当worker处理无阻塞事件时会一直处理直至完成或阻塞(个人猜测,或许也会有time上限,没看源码哈),一旦遇到阻塞,则继续处理下一事件。这样的好处是能够最大限度的发挥系统的性能。

由于nginx会把动态请求转发给php-fpm处理,所以动态请求优化,我认为就是针对php-fpm的优化了。

当nginx的worker_processes为8,采用epoll,worker_connectins=1024;php-fpm 使用static的pm方式,并且max_children=64的时候,访问有数据库(前端有memcached缓存)访问的页面,没有加eAccelerator加速器的时候,QPS只能达到40。加上eAccelerator,QPS达到150左右。

将上面的worker_connections改为65535,并更改响应的ulimit,QPS反而下降到100左右。

访问同样的页面,使用apache,QPS是37。

————————————————————–

2012-03-16

针对新买的虚拟服务器做了性能测试,centos,2.6.18核,nginx1.14,php5.3,使用php-fpm。使用http_load作为压力测试工具。

2核4G内存:
QPS 90+-(必须使用memcached,否则性能很差),cpu100%,load20+,  http_load使用不同的参数组合,基本不变,php-fpm配置为dynamic模式,则nginx的errorlog中有timout:connect() failed (110: Connection timed out) while connecting to upstream
QPS 70+- ,static,无timeout,cpu100%,load20+
(可通过pstree | grep php-fpm查看当前php-fpm子进程个数)
4核8G内存,php-fpm dynamic, max_children 128:CPU idle65% , 负载个位数,不超过8
-parallel 200 -fetches 2000  QPS 170
-parallel 300 -fetches 3000  QPS 120 (有connect timeout了)推测是来不及clone子进程,故改为static测试如下
4核8G内存,php-fpm static, max_children 256:CPU idle65% , 负载个位数,不超过8
-parallel 300 -fetches 3000  QPS 150 (无connect timeout了)

在2核4G机器上测试时,dynamic模式,即使timeout出现时,php-fpm进程数都没有达到pool的max_children个数,启动个数是5,最大个数是128,在短期大量请求时,只能达到六七十个php进程。同时cpu使用100%,us大约80%-90%,负载达到30左右。strace挂到php-fpm master进程上看时,发现clone请求时有略微停顿。所以,猜测是,瓶颈在cpu,php子进程已经占用了大量的cpu资源,本来就在相互竞争cpu了,同时也导致master进程无法快速增加子进程,所以造成响应缓慢,QPS也不高

我们有这样一个web需求:存入一批item,每个item有一个唯一的id,其他数据还包括title、pic、price等。写入目前由人工后台编辑(今后可能会被算法给出),删除也由后台人工和定时任务完成。该数据会被频繁读取,前台读取这些数据的时候,需要从一批(初始在百-千数量级)item里选出10-20个进行展示。

不想放在数据库里,一方面是出于效率考虑,再一方面是针对这种灵活需求,不想建表,而且cabinet本身的永久存储和高效读取也很好用。

我用的是php,使用TokyoTyrant扩展。有两种选择:

  1. 将所有的id存放在一个key-value对item_total中,每个item单独存放在一个key-value对item_[id]。当读取的时候,先读出item_total中的内容,shuffle,随机获取一批ids,再从item_[id]里读取具体的内容。
  2. 每个item单独存放在一个key-value对item_[id]。读取时,先使用fwmKeys获取所有以item_开头的keys,随机获取一批,再从item_[id]里读取具体内容。

测试了两者的效率:单线程。在item_total里存储了1w条ids,获取并随机100次;从item_前缀里获取1w条,再随机获取。两者的时间差不多,都在1s左右,方法1稍快。

编码的便利性方面:方法1,需要多维护一个item_total。方法2,只需要操作item_[id]即可。

最后,想看看两者的具体区别。我使用的B+tree cabinet存储类型。

当使用方法1的时候,需要调用php的fwmKeys方法。TokyoTyrant调用到tokyotyrant里的tcrdbfwmkeysimpl方法,向cabinet server发送socket请求,封装的请求命令是TTCMDFWMKEYS。server端即tokyocabinet的tcbdb.c中的tcbdbfwmkeys方法最终处理该请求:

/* Get forward matching keys in a B+ tree database object. */
  TCLIST *tcbdbfwmkeys(TCBDB *bdb, const void *pbuf, int psiz, int max){
    assert(bdb && pbuf && psiz >= 0);
    TCLIST *keys = tclistnew();
    if(!BDBLOCKMETHOD(bdb, false)) return keys;
    if(!bdb->open){
      tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__);
      BDBUNLOCKMETHOD(bdb);
      return keys;
    }
    tcbdbrangefwm(bdb, pbuf, psiz, max, keys);
    bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum;
    BDBUNLOCKMETHOD(bdb);
    if(adj && BDBLOCKMETHOD(bdb, true)){
      tcbdbcacheadjust(bdb);
      BDBUNLOCKMETHOD(bdb);
    }
    return keys;
  }

这里注意到BDBLOCKMETHOD和BDBUNLOCKMETHOD方法。第一次调用的是非独占性锁,第二次调用的是写入锁。

当使用方法2的时候,由于cabinet中有多个get方法,没有具体定位到,但是大致浏览和猜想了一下,肯定不会有写入锁。

所以,综合考虑,还是使用方法2,以应用web中的大量并发访问。

mysql和web服务器分开了,感觉页面打开好慢。在测试服务器根本没有这个问题,分开了应当更快才到,但是反而更慢了。记得以前改过这样的问题,时间长了,淡忘了。老了,记性不好了。哈哈。

解决方法:

[mysqld]
skip-name-resolve

在mysqld中加上skip-name-resolve,重起mysql就OK了。

这样也会产生问题,

GRANT ALL ON test.* TO dba@localhost

这里的localhost是域名,是没法解释的,只能用IP了

zz from: http://blog.51yip.com/mysql/1339.html

今天新搞了一个表,其中有个字段如下:

type enum(‘1tag’, ‘0product’)

因为排序的时候需要有类似的句子:order by weight desc, type asc, id desc 。所以想着把type前面加上数字,用来排序。

结果order的时候,本来相同weight的,应该0product在前面,却一直在后面。

后来思考才想起来,enum其实是数字类型,1tag对应的是0,0product对应的才是1!所以,为了意思明确,还是把字段类型改为:

type enum(‘0product’, ‘1tag’)吧。

匆匆忙忙的十一过去了,东跑西跑反而落下了修佛的功课,心情有些浮躁,开始有一些不开心的情绪。下午,站在窗前,看外面迷雾重重,就像我心中缴杂着的事情。

但是,佛陀最开始宣说的,不正是苦集灭道的四圣谛吗?人生本苦,如果一味去追求世俗的快乐、完美,只会让自己越来越焦躁。比如说,我没有办法让所有的流浪猫、狗不受到伤害,也没法把妈妈接到北京的同时也赡养我的姥姥。世俗间的事情,就像乱麻,如果顺着它去走,只会把自己变成乱麻的一分子。

只有感觉到苦,才会去探究苦的根源,也就是集。苦的根源,是无常啊!生命起起落落,念头也起起落落,我无法控制生老病死,也无法操纵别人的念头,所有当别人有某些不好的念头,针对我或者不针对我,其实都正常,能帮忙纠正便纠正,否则佛陀尚且不度无缘之人呢。如果我的心也随之流动,那就不但人度不成,我也沉沦苦海了。

知道诸行无常,自然而然的,就不与之较真。正如净空老法师说的,放下、自在。走到的这一步,不是别人走的,正是我自己,若有错便虔诚忏悔,而后踏实前行。正该关注的是,当下我迈起的步子,和它应该落在哪里。善行,并且掌控自己的内心,这才是修行佛法

但是,这也从一个侧面反映我的修为远远不够,仅仅落下不到十天的功课,心就随境而转。不可再放逸!

—————————————————

这次回家也不是没有收获的。当我自己心静的时候,才可以更通透的看待人和事。

第一惊喜的是,我褪下自己手上一直用来计数的念珠,准备给姥姥戴上时,她一点都没推让,很自然的接受了!而且之后,我教她念“阿弥陀佛”,人家本来就会,还答应会经常念!

第二惊喜的是,妈妈喜欢看看《和谐拯救危机》,能听进净空老法师的讲话,还推荐给她同事了,她同事还准备组团去拜访庐江县汤池镇。

其他的收获还有,两个同学也对佛法不反感。去山上上坟的时候,心情是平静的,长辈们没做什么坏事,应当不会堕入恶道吧!

其实,现在想来,能够和别人交谈佛法,首先是因为佛法真正的改变了我的行为,使别人会好奇并消除对佛法的敌意。其次,不再在意言语中的得失,少了很多针锋相对,自然和谐。有些话,虽然本意是好的,但是对方暂时无法接受,那就先不说,保持一个良好的氛围,之后再随缘说起。

真诚的希望,姥姥和妈妈能够与佛结缘,我受益匪浅,希望我最亲的人也可以分享。