5月 27

从mysql向redis中加载数据测试

  有测试显示reids如果使用持久化测试后效率会下降,所以不使用持久化。现在来测试一下从mysql中捞取数据加载到redis中的速度。
  服务器使用8核2.6 cpu,内存8G,sas硬盘,Centos5.6 64位操作系统。python 2.6 redis2.4.13.
  使用测试代码如下,从mysql的photo表中捞取两列数据加载到redis中,这两列在表中都有索引,数据量28万。

#!/bin/env python
# -------------------------------------------------
# Filename:    
# Revision:    
# Date:        2012-05-27
# Author:      simonzhang
# Email:       simon-zzm@163.com
# -------------------------------------------------
import MySQLdb
import redis


def redis_run(sql_data):
    try:
        r = redis.Redis(host='192.168.1.100', password = '123456', port=6379, db=0)
    except redis.RedisError, e:
        print "Error %s" % e
    for i in sql_data:
        r.set(str(i[0]),i[1])
        

def mysql_run(sql):
    try:
        db = MySQLdb.connect(host='192.168.1.100', user='test', passwd ='123456', db='photo')
        cursor = db.cursor()   
    except MySQLdb.Error, e:
        print "Error %d:%s" % (e.args[0],e.args[1])
        exit(1)
    try:
        result_set = ''
        cursor.execute('%s' % sql)
        result_set=cursor.fetchall()
        cursor.close()
        db.close()
        return  result_set
    except MySQLdb.Error, e:
        print "Error %d:%s" % (e.args[0], e.args[1])
        cursor.close()
        db.close()

def main():
    _loop = 0
    _limit_start = 0
    _limit_span = 10000
    _count_result = 5
    while _count_result > 0:
        result_data = ''
        sql = "select id as pid, userid as uid from photo LIMIT %s,%s" % (_limit_start + _limit_span * _loop, _limit_span)
        result_data = mysql_run(sql)
        _count_result = len(result_data)
        redis_run(result_data)
        _loop += 1


if __name__ == '__main__':
    main()

进行测试,分别为每次捞取50万,10万,5万,1万,结果如下:

50万
real 0m26.239s
user 0m16.816s
sys 0m5.745s

10万
real 0m24.019s
user 0m15.670s
sys 0m4.932s

5万
real 0m26.061s
user 0m15.789s
sys 0m4.674s

1万
real 0m28.705s
user 0m15.778s
sys 0m4.913s

结论:每次捞取10万效率会比较理想,对于操作系统的压力不大,所以硬件方面不用考虑。
这里两列保存的都是id,加入用户id和照片id长度都是9位,一组数据是18位。一亿组数据也就需要2G内存。
通过计算28万需要24秒,如果有1亿的数据,全部倒入要2个半小时。所以内存存储不是问题。不知道用固态硬盘是否能快,我没有就不知道了。所以要做三件事,一做好集群,将数据及时同步到其他机房,自己写个程序同步定时同步,如果用主从,主机重启了为空,这个就很麻烦了,二使用redis的数据持久化,肯定比从mysql中直接捞快,三天天烧香希望不要宕机。

4月 12

C 语言 读取mysql

测试环境:CentOS 5.4 64位 mysql5.5.20
mysql使用bin安装,安装在/program/mysql目录

代码

#include 
#include 
#include 
#define GET_ARRAY_LEN(array,len) {len = (sizeof(array) / sizeof(array[0]));}

int main(int argc,char **argv )
{
    MYSQL *sql_p;
    MYSQL_RES *result_p;
    MYSQL_ROW row_p;
    int res;
    int len;
    sql_p=mysql_init(NULL);
    if(sql_p==NULL){
        printf("Init error!\n");
        exit(1);
    }

    sql_p=mysql_real_connect(sql_p,"192.168.1.41","root","test",
                    "mysql",0,NULL,0);
    if(!sql_p){
        fprintf(stderr,"%d:%s\n",mysql_errno(sql_p),mysql_error(sql_p));
        exit(1);
    }

    res=mysql_query(sql_p,"SELECT * FROM admin");
    if(res){
        printf("Select error!\n");
        exit(1);
    }
    
    result_p=mysql_use_result(sql_p);
    if(!result_p){
        printf("mysql_use error!\n");
        exit(1);
    }

    row_p=mysql_fetch_row(result_p);
    GET_ARRAY_LEN(row_p,len);
    printf("%d\n",len);
    int i;
    for (i=0 ;i<20 ;i++)
      {if (row_p[i][1])
         printf("%s\n",row_p[i]);
       }
    mysql_close(sql_p);
    return 0;
}

编译语句
gcc -Wall cmysql.c -o cmysql -L /program/mysql/lib -I /program/mysql/include/ -lmysqlclient -lz

问题:
运行报错
./cmysql: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object file: No such file or directory

解决办法:
32位操作系统运行下面一句
ln -s /usr/local/mysql/lib/libmysqlclient.so.18 /usr/lib/
64位操作系统运行下面一句
ln -s /usr/local/mysql/lib/libmysqlclient.so.18 /usr/lib64/
再次编译通过。
在读取数据时还出现一个问题,如果没有数据,程序显示错误,这个我没有处理。

2月 17

mysql 升级5.5.20 注意问题记录

当前使用mysql5.1但是有些表情字符不能加入,所以决定将数据库
升级到5.5.20。从官方下载二进制64位工具。
http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.20-linux2.6-x86_64.tar.gz/from/http://mysql.cs.pu.edu.tw/

直接解压,将老版本的数据直接拷贝过来,启动数据库。整个过程比较顺利,
数据库已经运行,为了避免以下错误,还需要进行以下操作。

a) 错误1548 – Cannot load from mysql.proc. The table is probably corrupted.

需要对数据进行升级。执行以下命令。
$ mysql_upgrade -u root -p
在出现一堆ok后升级完成。

b) 岁然数据库和数据升级了,还需要修改表的字符集。(根据需要进行修改)

登录mysql,进入相关库,使用如下命令。
> alter table xxxx charset utf8mb4;
当前数据库可以支持iphone表情和奇怪的字符集了。

升级过程注意保存原有配置。

9月 27

[转发] nodejs下mysql性能测试

nodejs下mysql性能测试

By qingdu on 2011 年 02 月 14 日
本文为原创文章,出自http://cnodejs.org,转载请注明出处和作者
作者:qingdu
原文:http://cnodejs.org/blog/?p=404

近期对node下的几个mysql操作库做了一下简单的调研
主要是针对这3个module进行
libmysqlclient,mysql-native, mysql

node-libmysqlclient

https://github.com/Sannis/node-mysql-libmysqlclient
基于libmysql的封装, 支持阻塞与非阻塞两种操作方式,目前在query部分功能比较完善,prepare statement方面还是有些bug,实际测试中一直出core

安装

npm install mysql-libmysqlclient

node-mysql

https://github.com/felixge/node-mysql
纯node的实现, 支持prepare statement, 数据的获取支持事件与callback两种方式

安装

npm install mysql

node-mysql-native

https://github.com/sidorares/nodejs-mysql-native

纯node的实现, 内置有简单的连接池支持,支持prepare statement, 数据的获取只支持通过事件方式

安装

npm install mysql-native

测试设计

测试表结构

CREATE TABLE `test10` (
`id` int(10) unsigned NOT NULL DEFAULT '0',
`txt` varchar(500) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

测试数据

分别生成了含10, 100, 500, 1500行记录的4张表
使用10个并发连接分别对其进行SELECT * FROM table的查询

测试结论

NewImage.jpg

其中数值表示qps值

在结果集较小时node-mysql-native明显胜出
当结果集增大到接近100行时,node-libmysqlclient开始表现出更佳的性能
node-mysql性能与其他两个module差距比较大,如果对性能有一定要求的话,则其基本不可用

测试代码

http://code.google.com/p/cnodejs/source/browse/#svn%2Ftrunk%2Fmysql-benchmark

9月 11

mysql双机热备恢复问题

Mysql中双机热备比较常见。运维过程中遇到一个问题,备机或主机的其中一台遇到硬盘物理故障,重装系统后需要重新同步数据。这时就遇到了一个问题,用“FLUSH TABLES WITH READ LOCK;”命令锁上所有表或者再mysqldump数据时使用“–lock-all-tables”或“–master-data”参数导出数据,但是数据库被锁不能操作,前台业务会报错,问题很严重。在oracle中有SCNThe System Change Number),在mysql的二进制日志中有position,所以只能从此处考虑。

所以我写一个脚本,思维逻辑如下:

a) 使用语句“show master statusG;” 获得导出开始的position的点

b) 开始导出整库数据

c) 导出完毕,再使用语句“show master statusG;” 获得导出结束的position的点

d) binlog中导出开始position点到结束position点得变化的增量数据

导入逻辑:

a) 先导入整库数据

b) 再导入增量的数据

c) 然后确认开始同步的position点,开始同步

做增量的数据需要使用mysql自带的mysqlbinlog命令,mysqlbinlog也可以远程使用,为了防止网络问题所以没有采用远程的方案。

Mysqlbinlog命令的主要参数如下:

-d, –database=name 仅列出该数据库相关的

-F, –force-if-open 强行读出正在使用的二进制文件

-j, –start-position=# 开始读取点

–stop-position=# 结束读取点

 –start-date 开始获取时间

 –stop-date 结束获取时间

导出完毕,在备机上先恢复整库文件,再恢复增量文件,再设置恢复点。还有几个文件问题没有太仔细考虑,如备份过程中二进制日志切换,数据量大的时候会出现增量和整库的重复等问题未考虑。本处只是抛砖引玉。

脚本如下(注意折行问题):

#!/bin/sh

#————————————————

# file name: mysql_dump_binlog.sh

# Revision: 1.0

# Date: 2011-09-10

# Author: simon-zzm

# Email: simon-zzm@163.com

# ———————————————–

#############set bases value

mysql_path=’/usr/local/mysql’

dump_path=’/usr/local/checksystem’

mysql_host=’192.168.1.12′

mysql_user=’root’

mysql_pass=’qq’

mysql_data=’test’

#############main

start_time=`/bin/date +%Y-%m-%d %H:%M:%S`

${mysql_path}/bin/mysql -h${mysql_host} -u${mysql_user} -p${mysql_pass} -e ‘show master statusg;’>/tmp/mysql_start_read_mast

get_start_f=`tail -1 /tmp/mysql_start_read_mast|/bin/awk ‘ ”{print $1}’`

#${mysql_path}/bin/mysqldump -h${mysql_host} -u${mysql_user} -p${mysql_pass} ${mysql_data}>${dump_path}/${mysql_data}_${now_time}.sql

sleep 30

${mysql_path}/bin/mysql -h${mysql_host} -u${mysql_user} -p${mysql_pass} -e ‘show master statusg;’>/tmp/mysql_end_read_mast

get_end_p=`/usr/bin/tail -1 /tmp/mysql_end_read_mast|/bin/awk ‘ ”{print $2}’`

get_end_f=`/usr/bin/tail -1 /tmp/mysql_end_read_mast|/bin/awk ‘ ”{print $1}’`

echo “dump database ${mysql_data} ok.”

stop_time=`/bin/date +%Y-%m-%d %H:%M:%S`

${mysql_path}/bin/mysqlbinlog -d${mysql_data} -F –start-date=”${start_time}” –stop-date=”${stop_time}” ${mysql_path}/data/${get_start_f}>${dump_path}/${mysql_data}_repair_${now_time}.sql

echo “CHANGE MASTER TO MASTER_LOG_FILE=’${get_end_f}’,MASTER_LOG_POS=${get_end_p} ; “

/bin/rm -rf /tmp/mysql_start_read_mast /tmp/mysql_end_read_mast

echo “repair database ${mysql_data} ok.”