Z9G's NOTES

python + c = nuclear

启用zhanglipeng.com域名

以前一直觉得用自己姓名全拼的域名太高调,不符合我一贯低调的作风 ///^_^…….
但是看着自己姓名全拼的域名没人注册,不注册又对不起自己的名字,于是鼓足了勇气注了下来,并且从今天开始正式启用 (^_^)
为了减少更换域名导致的搜索引擎收录的损失,将原blog整站跳转到现在的地址,这是原blog目录.htacess的配置,用这个配置可以将x-mind.com/blog下的url全部301跳转到zhanglipeng.com/blog下对应的url。

RewriteEngine On
RewriteBase /blog/
RewriteCond %{HTTP_HOST} ^x-mind.com$ [NC]
RewriteRule ^(.*)$ http://zhanglipeng.com/blog/$1 [R=301,L]

浅析 Django runserver 的 autoreload 功能

在一个django项目中用python manange.py runserver启动一个内置server以后, 当修改了这个项目的某个python文件,内置的server会自动重启以加载新的文件,这个功能看上去很cool, 大大节省了开发调试过程中手动重启server的时间。 今天抽空看了一下其实现的代码, 发现原来这个autoreload的功能是可以完全独立于django的一个模块。
runserver是django management的一个command, 源文件位置在 django目录/core/management/commands/runserver.py, 在文件的最后可以看到这样几行代码:

 if use_reloader:
     from django.utils import autoreload
     autoreload.main(inner_run)
 else:
     inner_run()

不难看出, 真正干活的其实是inner_run, 而负责自动重启server的是django.utils里面的autoreload.
是否reload的判断条件都是检查sys.modules中各个模块文件的最后修改时间是否有所变化, 但是由于python和jython的线程机制的不同,autoreload.py针对python和jython做了不同的处理, jython reloade的实现:

def jython_reloader(main_func, args, kwargs):
    from _systemrestart import SystemRestart
    thread.start_new_thread(main_func, args)
    while True:
        if code_changed():
            raise SystemRestart
        time.sleep(1)

相比较python环境下的实现要稍微发杂些, python_reloader 设置一个环境变量RUN_MAIN,然后复制一个当前进程的子进程(不是线程哦), 然后在这个新进程中启动一个线程去真正干活儿,一个线程检查文件是否修改,当有文件修改的时候, 退出新启动的进程( sys.exit(3) ), 这时父进程会判断是否是因为修改文件导致(返回码为 3), 是则再启动一个新进程去干活儿, 否则整个程序退出。
具体细节还是看代码更清晰一些, 整个autoreload的代码跟django没有耦合, 可以单独使用。
如是做了如下尝试:

from django.utils import autoreload

def tt():
    print 'aaa...'
    while True: pass

autoreload.main(tt)

保存,然后在命令行运行之,期间修改源码,将print ‘aaa…’改成print ‘bbb…’, 保存, 可以看到之前运行的程序输出为:

$ python tt.py
aaa...
bbb...

可见在调试一个daemon程序的时候,通过autoreload加入自动加载功能是多么easy的事情了 :)

补充:之后又看了以下webpy的内置server的reload功能的实现,在webpy的application.py中能找到reload的时间, 大致原理是每个request都做一下是否reload的检查, 耦合度比较紧。

在Dreamhost上搭建python2.6环境

Dreamhost默认有python2.4和python2.5,想用python2.6就得自己安装了,下面是安装python2.6的步骤:
1. python

wget http://www.python.org/ftp/python/2.6.5/Python-2.6.5rc2.tgz
tar xzvf Python-2.6.5rc2.tgz
cd Python-2.6.5rc2
./configure --prefix=/your/path/to/install

echo "export \$PATH=\$PATH:/your/path/to/insall/bin" >> ~/.bash_profile

2. setuptools
到 http://pypi.python.org/pypi/setuptools 下载 Python2.6 相应版本的 setuptools

. ~/.bash_profile
wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg#md5=bfa92100bd772d5a213eedd356d64086
chmod +x setuptools-0.6c11-py2.6.egg
./setuptools-0.6c11-py2.6.egg

3. MySQLdb

easy_install-2.6 easy_install MySQL-python

注意:用easy_install的方式安装MySQLdb, 用的名字是MySQL-python

MySQL性能优化/调优:默认配置的修改

  最近做了一些MySQL Tuning的工作, 发现一些MySQL的默认配置是不合理的。 在这里罗列一下这些配置, 每次新装MySQL的时候, 最好根据实际需要调整一下这些配置:

max_connections
  最大并发连接数。当MySQL的并发连接达到这个设定值时,新的连接将会被拒绝。当发现MySQL有能力处理更多的并发的时候, 建议调大这个值,相应给服务器带来更高的负载(CPU/IO/内存)。
  默认值:100, 参考设置:900

back_log
  TCP/IP连接队列的最大值。当MySQL同时有大量连接请求的时候,MySQL会尝试用当前现有的线程处理这些请求,如果处理不过来,MySQL会把连接先放到一个队列里面,然后起新的线程处理。这个过程会很快, 但是并发请求很多的话,需要调高这个值,否则新来的连接请求会被拒绝。在一次压测的时候发现客户端返回大量的“Lost connection to MySQL”, 就是因为back_log的默认值太小导致的。增大这个值会增大CPU负载并消耗更多的内存。
  默认值:50, 参考设置:200

skip-name-resolve
  关闭反向域名解析。MySQL默认会对每个客户端连接作反向域名解析,强烈建议关闭反向域名解析。关闭的方法是在my.cnf里面加一行skip-name-resolve

innodb_file_per_table
如果使用innodb, 强烈建议打开这个设置,否则所有的innodb表共享一个文件,并且这个文件的大小不会因为表数据的减少而减小,时间长了会把磁盘搞爆,这是mysql的一个bug:http://bugs.mysql.com/bug.php?id=1341

max_connect_errors
  当客户端连接服务端超时(超过connect_timeout), 服务端就会给这个客户端记录一次error,当出错的次数达到max_connect_errors的时候,这个客户端就会被锁定。除非执行FLUSH HOSTS命令。绝对是个地雷!
  默认值:10, 参考设置:1844674407370954751(能设多大,设多大)

connect_timeout
  连接超时的秒数。
  默认值:5, 参考设置:15
  
slave_net_timeout
  MySQL主从复制的时候, 当Master和Slave之间的网络中断,但是Master和Slave无法察觉的情况下(比如防火墙或者路由问题)。Slave会等待slave_net_timeout设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据。默认是3600秒,相信一个小时之后,黄花菜都凉了。
  默认值:3600, 参考设置:30

wait_timeout
  连接过期秒数。当一个连接SLEEP超过wait_timeout秒后,MySQL服务端会中断这个连接。这个值设置的过长有可能会导致大量的SLEEP链接占用系统资源,过小会导致“MySQL has gone away”的错误。
  默认值:28800, 参考设置:30

key_buffer
  主键缓存。如果发现有大量的slow log,可以尝试调高这个值,相应会带来更高的内存开销。

table_cache
  给经常访问的表分配的内存。调大这个值,一般情况下可以降低磁盘IO, 但是相应会占用更多的内存。

配置的查看

mysql> show variables like "max_%";
+----------------------------+----------------------+
| Variable_name              | Value                |
+----------------------------+----------------------+
| max_allowed_packet         | 31457280             |
| max_binlog_cache_size      | 18446744073709547520 |
| max_binlog_size            | 1073741824           |
| max_connect_errors         | 10                   |
| max_connections            | 100                  |
| max_delayed_threads        | 20                   |
| max_error_count            | 64                   |
| max_heap_table_size        | 16777216             |
| max_insert_delayed_threads | 20                   |
| max_join_size              | 18446744073709551615 |
| max_length_for_sort_data   | 1024                 |
| max_prepared_stmt_count    | 16382                |
| max_relay_log_size         | 0                    |
| max_seeks_for_key          | 18446744073709551615 |
| max_sort_length            | 1024                 |
| max_sp_recursion_depth     | 0                    |
| max_tmp_tables             | 32                   |
| max_user_connections       | 0                    |
| max_write_lock_count       | 18446744073709551615 |
+----------------------------+----------------------+

配置的修改
动态变量可以在MySQL命令行里面设置:

mysql> set global max_connections = 1600;
Query OK, 0 rows affected (0.02 sec)

非动态变量,比如back_log只能在my.cnf里面修改,修改后重启MySQL才能生效:

back_log=200

Read the rest of this entry »

MySQL Log 的配置

MySQL内置4种Log:
Error Log, General Query Log, Binary Log, Slow Query Log

1. Error Log
错误日志, 记录MySQL启动、运行、停止过程中出现的错误信息

2. General Query Log
记录MySQL客户端连接、查询的细节, 调试的时候很有用, 正式运行的时候最好关闭否则会带来大量磁盘IO
可以在my.cnf设置
log = your-path-to-general-log

3. Binary Log
记录数据的修改, 配置MySQL主从复制时需要打开

4. Slow Query Log
记录不用索引的Query和执行时间超过long_query_time指定的秒数的Query
可以在my.cnf设置
long_query_time = 5
log-slow-queries = your-path-to-slow-log

更多内容:MySQL 手册

MySQL “Unable to lock ./ibdata1, error: 35” 的解决

问题的出现因为一次MySQL的非正常退出,MySQL正在执行一个耗时的查询导致用mysql-server stop一直等待,于是我在shell里面kill -9 mysql,再次启动mysql的时候报错,MySQL error log最后几行:

InnoDB: Unable to lock ./ibdata1, error: 35
InnoDB: Check that you do not already have another mysqld process

解决方法:

cd your-mysql-db-dir
mv ibdata1 ibdata1.bak
cp -a ibdata1.bak ibdata1

然后启动mysql ibdata1的lock问题得解,但是随之而来的是漫长的innodb的恢复,如果数据量大,恢复的时间会比较长。250+G的数据用了大概2个小时才恢复完, 这个时候不要去kill mysqlserver, 虽然在恢复的过程中还不能用客户端登录mysqlserver。

总结:这次问题的出现因为一次生硬的kill, 当出现MySQL因为有耗时的查询导致MySQL Server无法退出的时候, 应该进入用mysql的交互shell里面kill, 而不要直接在shell里面做kill.

MySQL 主从复制的配置

1. 主服务器的配置
my.cnf:

[mysqld]
log-bin=mysql-bin
server-id=1

server-id的值必须是 1 到 2^32-1 之间的正整数

2. 在主服务器上创建复制使用的帐户

GRANT REPLICATION SLAVE ON *.* TO "replication_user_name"@"slave_host_name" IDENTIFIED BY 'replication_password';
SHOW MASTER STATUS;

3. 备份数据
冷备份:直接停mysqld
热备份:

  • flush tables;
  • show master status; 记录下File和Position
  • unlock tables;

复制数据:

  • 拷贝master的mysql 数据目录到slave上
  • 删除slave mysql数据目录下的master.info和relay-log.info
  • chown -R mysq:mysql slave的mysql 数据目录

4. 从服务器的配置
my.cnf:

[mysqld]
server-id=2

这里的server-id不能跟master的server-id重复

CHANGE MASTER TO
  MASTER_HOST='master_host_name',
  MASTER_USER='replication_user_name',
  MASTER_PASSWORD='replication_password',
  MASTER_PORT=master_host_port,
  MASTER_LOG_FILE='recorded_log_file_name',
  MASTER_LOG_POS=recorded_log_position,
  MASTER_CONNECT_RETRY=10;

SLAVE START;
SHOW SLAVE STATUS;

如果SHOW SLAVE STATUS 结果中
Slave_IO_Running=Yes
Slave_SQL_Running=Yes
表示同步成功。

Tokyo Cabinet 和 Tokyo Tyrant 的实用工具

查看状态

echo -ne "stats\r\n\r\n" | nc 127.0.0.1 1978

插入单条数据

tcrmgr put -port 1978 127.0.0.1 your_key "your_value"

批量导入数据

tcrmgr importtsv -port 1978 127.0.0.1 your_tsvfile

批量导出数据

tcrmgr list -port 1978 127.0.0.1 > ouput_file

FreeBSD 下 MySQL 单机多实例的配置

目标:
单台FreeBSD服务器,启多个MySQL服务, 每个服务有单独的pid和数据库目录
单个MySQL实例的情况下可以通过/usr/local/etc/rc.d/mysql-server启动MySQL实例。
要启动多个MySQL实例,可以复制/usr/local/etc/rc.d/mysql-server,然后稍作修改即可。

1. 建立数据库存放目录
mkdir /var/db/mysql0

2. 新建/usr/local/etc/rc.d/mysql-server-0
找到
: ${mysql_dbdir="/var/db/mysql"}

修改成
: ${mysql_dbdir="/var/db/mysql0"}

找到


command_args="--defaults-extra-file=${mysql_dbdir}/my.cnf --user=${mysql_user} --datadir=${mysql_dbdir} --pid-file=${pidfile} ${mysql_args} > /dev/null 2>&1 &"

修改成

command_args="--defaults-file=${mysql_dbdir}/my.cnf --user=${mysql_user} --datadir=${mysql_dbdir} --pid-file=${pidfile} ${mysql_args} > /dev/null 2>&1 &"

3. 新建my.cnf配置文件
# cp /etc/my.cnf /var/db/mysql0
# vi /var/db/mysql1/my.cnf

找到
[mysqld]
port = 3306
socket = /tmp/mysql.sock

修改成
[mysqld]
port = 3307
socket = /tmp/mysql0.sock

4. 启动新MySQL实例
/usr/local/etc/rc.d/mysql-server-0 start

5. 测试
mysql -h127.0.0.1 -P 3307

6. 添加更多的实例
依次遵循步骤1~5, 相应修改端口号(3307, 3308 …)和配置文件名(0, 1, …)即可

Tokyo Cabinet 和 Tokyo Tyrant 的安装

Tokyo Cabinet是个简单易用的高性能Key-Value DB, 现将安装配置记录如下:
安装前的准备
确认系统已经包含以下软件包:

  • gcc 3.1 或更高版本
  • zlib: 1.2.3或更高版本
  • bzip2: 1.0.5或更高版本
wget http://www.zlib.net/zlib-1.2.3.tar.gz
tar xzvf zlib-1.2.3.tar.gz
cd zlib-1.2.3
./configure
make
sudo make install

wget http://www.bzip.org/1.0.5/bzip2-1.0.5.tar.gz
tar xzvf bzip2-1.0.5
cd bzip2-1.0.5
make
sudo make install

安装 Tokyo Cabinet 1.4.23:

wget http://downloads.sourceforge.net/sourceforge/tokyocabinet/tokyocabinet-1.4.23.tar.gz
tar xzvf tokyocabinet-1.4.23.tar.gz
cd tokyocabinet-1.4.23
./configure
make
sudo make install

至此,如果没有报错,Tokyo Cabinet已经安装成功, 将会生成以下文件:

/usr/local/include/tcutil.h
/usr/local/include/tchdb.h
/usr/local/include/tcbdb.h
/usr/local/include/tcfdb.h
/usr/local/include/tctdb.h
/usr/local/include/tcadb.h
/usr/local/lib/libtokyocabinet.a
/usr/local/lib/libtokyocabinet.so.x.y.z
/usr/local/lib/libtokyocabinet.so.x
/usr/local/lib/libtokyocabinet.so
/usr/local/lib/pkgconfig/tokyocabinet.pc
/usr/local/bin/tcutest
/usr/local/bin/tcumttest
/usr/local/bin/tcucodec
/usr/local/bin/tchtest
/usr/local/bin/tchmttest
/usr/local/bin/tchmgr
/usr/local/bin/tcbmgr
/usr/local/bin/tcbtest
/usr/local/bin/tcbmttest
/usr/local/bin/tcftest
/usr/local/bin/tcfmttest
/usr/local/bin/tcfmgr
/usr/local/bin/tcttest
/usr/local/bin/tctmttest
/usr/local/bin/tctmgr
/usr/local/bin/tcamgr
/usr/local/bin/tcatest
/usr/local/libexec/tcawmgr.cgi
/usr/local/share/tokyocabinet/...
/usr/local/man/man1/...
/usr/local/man/man3/...

安装 Tokyo Tyrant 1.1.27_1:

wget http://downloads.sourceforge.net/sourceforge/tokyocabinet/tokyotyrant-1.1.27.tar.gz
tar xzvf tokyotyrant-1.1.27.tar.gz
cd tokyotyrant-1.1.27
./configure
make
make install

同样,如果没有报错,Tokyo Cabinet已经安装成功, 将会生成以下文件:

/usr/local/include/ttutil.h
/usr/local/include/tculog.h
/usr/local/include/tcrdb.h
/usr/local/lib/libtokyotyrant.a
/usr/local/lib/libtokyotyrant.so.x.y.z
/usr/local/lib/libtokyotyrant.so.x
/usr/local/lib/libtokyotyrant.so
/usr/local/lib/ttskelmock.so
/usr/local/lib/ttskeldir.so
/usr/local/lib/ttskelproxy.so
/usr/local/lib/ttskelnull.so
/usr/local/lib/pkgconfig/tokyotyrant.pc
/usr/local/bin/ttserver
/usr/local/bin/ttultest
/usr/local/bin/ttulmgr
/usr/local/bin/tcrtest
/usr/local/bin/tcrmttest
/usr/local/bin/tcrmgr
/usr/local/sbin/ttservctl
/usr/local/share/tokyotyrant/...
/usr/local/man/man1/...
/usr/local/man/man3/...

验证
开启一个终端启动Tokyo Tyrant

ttserver

再开启一个终端

make check

Tokyo Cabinet 和 Tokyo Tyrant 已经成功安装, 可以开始你的东京之旅了 :)