9月 08

go语言连接mysql成功

  go语言取mysql数据。之前的测试并没有成功,也没有找到原因,但是今天编译了一下又成功了,具体修改了哪里我也忘了。赶紧做个记录。敏感信息已经隐藏

  获得go语言的mysql驱动
go get code.google.com/p/go-mysql-driver/mysql
也可以
驱动安装
go get github.com/go-sql-driver/mysql
go install github.com/go-sql-driver/mysql

2013-5-27修正:该mysql驱动被移到git以后使用“$ go get github.com/go-sql-driver/mysql”
项目里调用为“import _ “github.com/go-sql-driver/mysql””

源码如下:

package main

import ("database/sql"
         _ "code.google.com/p/go-mysql-driver/mysql"
        "fmt")

func main() {
    db, e := sql.Open("mysql", "simon:zhang@tcp(127.0.0.1:3306)/simonzhang?charset=utf8")
    if e != nil {
        print("ERROR")
        return
    }
    println("Conn DB OK")
    rows, e := db.Query("select user,passwd from user")
    if e != nil {
        fmt.Print("error:%v\n", e)
        return
    }
    if rows == nil {
        print("Rows is nil")   
        return
    }
    for rows.Next() {
        var u,p string
        err := rows.Scan(&u,&p)
        if err != nil {
            print("Row error!")
            return
        }
        fmt.Println(u," ",p)
    }
    println("WIN!")
}

运行结果

6月 18

tornado学习笔记(二)

主要模块

web – FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能
escape – XHTML, JSON, URL 的编码/解码方法
database – 对 MySQLdb 的简单封装,使其更容易使用
template – 基于 Python 的 web 模板系统
httpclient – 非阻塞式 HTTP 客户端,它被设计用来和 web 及 httpserver 协同工作
auth – 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth)
locale – 针对本地化和翻译的支持
options – 命令行和配置文件解析工具,针对服务器环境做了优化

底层模块

httpserver – 服务于 web 模块的一个非常简单的 HTTP 服务器的实现
iostream – 对非阻塞式的 socket 的简单封装,以方便常用读写操作
ioloop – 核心的 I/O 循环

  首先在建立一个mysql数据库,库名为test_tornado,建立一个有用户表,表中包含用户名密码,脚本如下。

CREATE TABLE `user` (
  `id` int(100) NOT NULL DEFAULT '0',
  `user` varchar(20) DEFAULT NULL,
  `passwd` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
);


INSERT INTO `user` VALUES ('0', 'simonzhang', '123456');

  建立监听,和url,启停脚本见上次笔记。
main.py

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import sys
import tornado.ioloop
import tornado.web
from login import *


application = tornado.web.Application([
    (r"/", LoginHandler),
],  cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")


if __name__ == "__main__":
    listen_port =  sys.argv[1]
    application.listen(listen_port)
    tornado.ioloop.IOLoop.instance().start()

  在同级目录下建立templates目录,在templates目录下建立login.html。login.html的源码是


   
      {{title}}
   
   
        
User Name:
Password:

  做一个简单的验证页面,只是个简单判断,学习使用,权限认证和cookie部分不做记录了。编辑login.py源码

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import sys
import tornado.ioloop
import tornado.locale
import tornado.web
import tornado.database
from dbmodel import *


class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("templates/login.html", title="simonzhan.net")
    def post(self):
        try:
            name = self.get_argument("login_username")
            passwd = self.get_argument("login_password")
            _passwd = get_passwd(name)
            if _passwd is not None:
                if _passwd == _passwd:
                    self.write("hello %s" % (_passwd))
                else:
                    self.render("templates/login.html", title="simonzhan.net")
            else:
               self.render("templates/login.html", title="simonzhan.net")
            #self.write("hello %s" % (name))
        except:
            self.render("templates/login.html", title="simonzhan.net")
            return

  因为要查数据,所以要用到database,将数据库部分放到一文件中去。编辑dbmodol.py源码如下:

#!/bin/env python
# -*- coding: utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
from tornado import database


def get_passwd(user_name):
    db = database.Connection("192.168.1.41","test_tornado","123456","simonzhang")
    for projects in db.query("SELECT user,passwd from user where user='%s'" % user_name):
        return projects.passwd

  启动服务,在ie里能看到页面,输入正确的账户密码,可以看到经典的话了。基本框架完成,剩下的慢慢学习,慢慢发挥了。

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中直接捞快,三天天烧香希望不要宕机。