12月 17

CentOS上使用python和C开发leveldb库学习测试

  测试环境为阿里云,单核Intel(R) Xeon(R) CPU E5-2420 0 @ 1.90GHz,内存512M,最基础的配置,测试系统为CentOS 64位。测试数据就是把双色球所有组合进行排列,共17721088行,文件名为di.txt,体积363421k。leveldb推荐使用SSD硬盘,当前虚拟硬盘的速度肯定是不行,此处只是学习,测试对比。

官方网址
http://code.google.com/p/py-leveldb/

安装命令
svn checkout http://py-leveldb.googlecode.com/svn/trunk/ py-leveldb-read-only
cd py-leveldb-read-only/
# 需要注意,下面的脚本里需要使用git获取leveldb。所以要把git客户端装好。
./compile_leveldb.sh
python setup.py build
python setup.py install

  python遇到的问题
  报错
../snappy-read-only/snappy.h:45:33: error: snappy-stubs-public.h

  解决:
yum -y install autoconf automake libtool
再次编译还是不成功,手动安装压缩工具。
网址:http://code.google.com/p/snappy/
使用命令
wget http://snappy.googlecode.com/files/snappy-1.1.1.tar.gz
./configure –enable-shared=no –enable-static=yes
make CXXFLAGS=’-g -O2 -fPIC’
make install
再次安装编译py-leveldb通过。

  C语言编译问题
  报错
/usr/bin/ld: cannot find -lleveld
collect2: ld 返回 1

  解决
将.so .a拷贝到系统lib目录中,测试系统64位,直接拷贝到lib64中。
cp libleveldb.* /usr/lib64/

python测试部分
顺序写代码

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:  
# Revision:    
# Date:        2013-12-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import leveldb
import time

db = leveldb.LevelDB('./data')

# multiple put/delete applied atomically, and committed to disk 
#batch = leveldb.WriteBatch()
f = open('di.txt')
num = 0
start = time.time()
for i in f:
    if i[-1] == '\n':
        data =  i[:-1]
    else:
        data = i
    num += 1
    db.Put("%s" % num, data)
end = time.time()
print "use sec %s" % (end-start)

批量写代码

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:  
# Revision:    
# Date:        2013-12-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import leveldb
import time

db = leveldb.LevelDB('./data')

batch = leveldb.WriteBatch()
f = open('di.txt')
num = 0
start = time.time()
for i in f:
    if i[-1] == '\n':
        data =  i[:-1]
    else:
        data = i
    num += 1
    batch.Put("%s" % num, data)
    # 因为内存太小,每5万行写入一次
    if ((num % 50000) == 0) or (num == 17721087):
        db.Write(batch, sync = True)
        batch = leveldb.WriteBatch()
end = time.time()
print "use sec %s" % (end-start)

随机读1000万次代码:

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:  
# Revision:    
# Date:        2013-12-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import leveldb
from random import randint
import time

db = leveldb.LevelDB('./data')
start = time.time()
for i in xrange(10000000):
    num = randint(1, 10000000)
    try:
        v =  db.Get("%s" % num)
        print v
    except:
        pass
end = time.time()
print "use sec %s" % (end-start)

测试结果
# python write_seq.py
use sec 329.217786074
每秒写入53827

# python write_bacth.py
use sec 173.626176119
每秒写入102064

# python read.py
use sec 288.070755005
每秒随机读取34713

C部分代码,为了方便,我把两个代码分开写。
C顺序写入

// Filename: 
// Revision:   
// Date:        2013-12-14
// Author:      simonzhang
// web:         www.simonzhang.net
// Email:       simon-zzm@163.com
// END INIT INFO
#include 
#include 
#include 
#include 
#include "leveldb/c.h"

char *itoa(int value, char *string, int radix)
{
    int rt=0;
    if(string==NULL)
        return NULL;
    if(radix<=0 || radix>30)
        return NULL;
    rt = snprintf(string, radix, "%d", value);
    if(rt>radix)
        return NULL;
    string[rt]='\0';
    return string;
}

int main()
{
    leveldb_t *db;
    leveldb_options_t *options;
    leveldb_readoptions_t *roptions;
    char *err = NULL;
    char *read;
    size_t read_len;
    time_t start_time, end_time;
    // write file
    FILE *di;
    if((di=fopen("di.txt","r"))==NULL)
    {
       printf("can't open!\n");
       return -1;
    }
    // OPEN leveldba
    options = leveldb_options_create();
//    leveldb_options_set_error_if_exists(options, 1);
//    leveldb_options_set_cache(options, cache);
//    leveldb_options_set_env(options, env);
//    leveldb_options_set_info_log(options, NULL);
//    leveldb_options_set_write_buffer_size(options, 100000);
//    leveldb_options_set_paranoid_checks(options, 1);
//    leveldb_options_set_max_open_files(options, 4096);
//    leveldb_options_set_block_size(options, 1024);
//    leveldb_options_set_block_restart_interval(options, 8);
//    leveldb_options_set_compression(options, leveldb_no_compression);
    leveldb_options_set_compression(options, leveldb_snappy_compression);
    leveldb_options_set_create_if_missing(options, 1);
    db = leveldb_open(options, "data", &err);

    if (err != NULL) {
      fprintf(stderr, "Open fail.\n");
      return(1);
    }
    leveldb_free(err);
    err = NULL;
    roptions = leveldb_readoptions_create();
    // start read
    start_time = time(NULL);
    int X=99,Y=15000000; //X为起始值 Y为终止值
    int _rand;//随机数
    char s[8];
    srand( (unsigned)time( NULL ) );
    for (int i = 0; i<10000000; i++)
    {
       _rand = rand()%(Y-X+1)+X;
       itoa(_rand,s,8);
       read = leveldb_get(db, roptions, s, strlen(s), &read_len, &err);
       //printf("%s\n", read);
       if (err != NULL) {
           fprintf(stderr, "Read fail.\n");
           return(1);
         }
        leveldb_free(err);
        free(read);
    }
    // CLOSE`
    leveldb_close(db);
    end_time = time(NULL);
    printf("%ld\n", end_time-start_time);
    return 0;
}

C 1000万次随机读

// Filename: 
// Revision:   
// Date:        2013-12-14
// Author:      simonzhang
// web:         www.simonzhang.net
// Email:       simon-zzm@163.com
// END INIT INFO
#include 
#include 
#include 
#include 
#include "leveldb/c.h"

char *itoa(int value, char *string, int radix)
{
    int rt=0;
    if(string==NULL)
        return NULL;
    if(radix<=0 || radix>30)
        return NULL;
    rt = snprintf(string, radix, "%d", value);
    if(rt>radix)
        return NULL;
    string[rt]='\0';
    return string;
}

int main()
{
    leveldb_t *db;
    leveldb_options_t *options;
    leveldb_writeoptions_t *woptions;
    char *err = NULL;
    time_t start_time, end_time;
    // write file
    FILE *di;
    if((di=fopen("di.txt","r"))==NULL)
    {
       printf("can't open!\n");
       return -1;
    }
    // OPEN leveldba
    options = leveldb_options_create();
//    leveldb_options_set_error_if_exists(options, 1);
//    leveldb_options_set_cache(options, cache);
//    leveldb_options_set_env(options, env);
//    leveldb_options_set_info_log(options, NULL);
//    leveldb_options_set_write_buffer_size(options, 100000);
//    leveldb_options_set_paranoid_checks(options, 1);
//    leveldb_options_set_max_open_files(options, 4096);
//    leveldb_options_set_block_size(options, 1024);
//    leveldb_options_set_block_restart_interval(options, 8);
//    leveldb_options_set_compression(options, leveldb_no_compression);
    leveldb_options_set_compression(options, leveldb_snappy_compression);
    leveldb_options_set_create_if_missing(options, 1);
    db = leveldb_open(options, "data", &err);

    if (err != NULL) {
      fprintf(stderr, "Open fail.\n");
      return(1);
    }
    leveldb_free(err);
    err = NULL;
    woptions = leveldb_writeoptions_create();
    // start write  
    start_time = time(NULL);
    char ch, str[30];
    int num=0, c=0;
    ch = fgetc(di);
    while(ch!=EOF)
    {
        if (ch == '\n') 
        {
            char s[10];
            itoa(num,s,10);
            leveldb_put(db, woptions, s, strlen(s), str, strlen(str), &err);
            if (err != NULL) {
                fprintf(stderr, "Write fail.\n");
                return(1);
            }
            memset(str,'\0',sizeof(str));
            c = 0;
            num += 1;
        }
        else
        {
            str[c] = ch;
            c += 1;
        }
        ch = fgetc(di);
    }
    fclose(di);
    // CLOSE
    leveldb_close(db);
    end_time = time(NULL);
    printf("%ld\n", end_time-start_time);
    return 0;
}

测试
C顺序写入
编译
gcc -Wall -std=c99 write-leveldb.c -lleveldb -O3 -o write-leveldb
结果
# ./write-leveldb
225
每秒钟处理78760

C 1000万次随机读
编译
gcc -Wall -std=c99 read-leveldb.c -lleveldb -O3 -o read-leveldb
结果
# ./read-leveldb
143
每秒处理69930

  写入过程CPU肯定是全部跑满。使用snappy压缩,所以写入data目录为175M,压缩了一半。
  随机读将CPU跑满。python内存占用23%。C语言占用内存最终增加到39%。
  之后又做到了一个测试,硬件内存只有512M,硬盘数据插入826M。使用python代码再次随机读取1000万次,使用347.94秒,每秒随机读28740。所以数据超出物理内存不会出错只是速度下降。
  还有问题一没有测试,leveldb默认的每块2M如果64G则数据文件65536个,达到系统打开文件最大数,不知道会不会出问题。并且在同一个目录下文件过多也会对系统改造成一定压力,不知道是否会有影响。推荐使用办法把单块体积加大,此效率也没有测试。
  还有一点说明,使用pypy做了测试,效果不如python,具体原因没有详查。

10月 11

Reids的安装、配置和初级管理

【2011-10-11 整理编辑 simon-zzm@163.com】

一、 获取和部署

# wget http://redis.googlecode.com/files/redis-2.2.12.tar.gz

# tar zxvf redis-2.2.12.tar.gz

# cd redis-2.2.12

# make

src目录下会生成可执行文件,可以使用make install 进行安装,默认安装后放在/usr/local/bin中。也可以制定存放目录make PREFIX=/some/other/directory。可执行文件的作用

redis-server 服务器的daemon启动程序

redis-check-aof 数据修复

redis-check-dump 检查导出工具

redis-cli 命令行操作工具

redis-benchmark 性能测试工具,测试Redis在你的系统及你的配置下的读写性能

直接执行redis-server,使用默认配置控制台打印。再redis-2.2.12中有redis.conf配置文件的模板,可以将配置文件放到认可位置,建议放到/etc下,使用配置文件启动redis命令如下。修改系统内核参数

# echo vm.overcommit_memory=1 >> /etc/sysctl.conf

# sysctl vm.overcommit_memory=1

使用数字含义:

0,表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。

2,表示内核允许分配超过所有物理内存和交换空间总和的内存

启动

# redis-server /etc/redis.conf

二、配置说明

配置文件主要参数说明如下(多个#为系统默认注释的配置):

daemonize no

#默认不以守护进程的方式启动,生产环境下建议改为yes

pidfile /var/run/redis.pid

#pid文件位置

port 6379

#监听端口

bind 127.0.0.1

#监听IP地址,可用于监听指定IP

unixsocket /tmp/redis.sock

#sock文件位置

timeout 60

#超时断开时间

loglevel verbose

#日志级别debugnoticeverbosewarning

logfile stdout

#日志保存位置,默认是输出到/dev/nul,既不记录日志。

# syslog-enabled no

# 开启系统日志,默认关闭

###### syslog-ident redis

######syslog-facility local0

# 日志级别从LOCAL0-LOCAL7

databases 16

#数据库个数,登陆数据库默认dbid0,可以使用select 设置。

save 900 1

save 300 10

save 60 10000

# 持久化保持 save *(秒数)*(修改次数)保存到硬盘上。全部注释掉,则不进行持久化。

rdbcompression yes

# 持快照是否要压缩

dbfilename dump.rdb

# 快照文件名称

dir ./

#快照保存位置

######slaveof

# 如果为从库需要配置主库的IP和端口,需要注意,从机如果做数据修改是不能同步到主机的

######masterauth

# 如果主数据库有密码需要在从库上设置主库的密码

###### requirepass foobared

< p>#主数据库的密码设置,如果加密了客户端连接为./redis-cli?-a foobared

slave-serve-stale-data yes

# 当主库宕机时,备机接替主库工作

######requirepass foobared

# 设置客户端登陆访问密码

maxclients 1024

# 默认客户端链接数,如果为0 则是不限制

######maxmemory 2048000000

# 使用内存大小,如果不设置为使用所有。单位为bytes

######maxmemory-policy volatile-lru

#内存用满的清理策略(lru为最近最少使用算法):

# volatile-lru:删除过期和lru key(默认值)

# allkeys-lru : 删除lru算法的key

# volatile-random:随机删除即将过期key

# allkeys->random:随机删除

# volatile-ttl : 删除即将过期的

# noeviction : 永不过期,返回错误

######maxmemory-samples 3

# 可以用ttl这只key的生存时间,此配置为用lru检查ttl时间。个人认为应该是对ttl的排序

appendonly no

# 开启操作记录日志,每此操作都会写日志,效率比较低。但是服务器宕机重启后,服务会加载日志,提高安全性。

#### appendfilename appendonly.aof

# 日志名称

appendfsync everysec

# 写日志的规则 always 时时写,everysec美秒写一次,no为不写

no-appendfsync-on-rewrite no

#没有太懂,个人理解是因为I/O效率问题,所以使用的一种类似的增量写入的方式。

slowlog-log-slower-than 10000

slowlog-max-len 1024

#像系统日志一样,记录命令的执行时间。记录周期为毫秒级(1000000毫秒=1秒)负值表示禁用,0表示记录所有命令。记录能保存的最大行数。

vm-enabled no

#虚拟内存开关

vm-swap-file /tmp/redis.swap

# 虚拟内存swap文件的位置。不同的redis服务不能共用内存文件。不推荐使用tmp目录。

vm-max-memory 0

#虚拟内存的大小,0为不限制。

vm-page-size 32

#缓存中每页的大小,默认是32个字节

vm-pages 134217728

# 虚拟内存中可以最大的页数,虚拟文件大小为vm-page-size * vm-pages。如果是32字节的页,用134217728页,会有4G大的swap文件

vm-max-threads 4

#使用虚拟内存的最大线程数

hash-max-zipmap-entries 512

hash-max-zipmap-value 64

list-max-ziplist-entries 512

list-max-ziplist-value 64

set-max-intset-entries 512

activerehashing yes

#为一种高级的哈希算法。原理没有明白,也不做修改了。

#以下为可以引入其它位置的配置文件。

# include /path/to/local.conf

# include /path/to/other.conf

三、基本管理

  Redis的命令共分为十个部分,其中主要的六个部分(KeyStringHashListSetSortedSet)的翻译可以到http://redis.readthedocs.org/en/latest/中查看。本问只是记录部分管理命令。

1Select

切换库,select后直接跟阿拉伯数字的dbid

举例:

redis 127.0.0.1:6379> select 1


OK

2Dbsize

统计库中key的数量

举例:

redis 127.0.0.1:6379> dbsize

(integer) 1

3Flushdb

Redis还支持对某个DB数据进行清除(当然清空所有数据的操作也是支持的)

redis 127.0.0.1:6379> dbsize

(integer) 1

redis 127.0.0.1:6379> flushdb

OK

redis 127.0.0.1:6379> dbsize

(integer) 0

4slaveof

同步命令,在从端参输入主机的IP和端口,进行数据同步。在复制的开始阶段处于阻塞状态(sync_readline)服务无法对外提供服务。

5Slowlog

获得slowlog日志中最近的2条记录

redis 127.0.0.1:6379> slowlog get 2

1) 1) (integer) 6

2) (integer) 1318257654

3) (integer) 19244

4) 1) “rpush”

2) “b”

3) “z”

2) 1) (integer) 5

2) (integer) 1318256413

3) (integer) 42203

4) 1) “keys”

2) “10*”

6Save Bgsave

将所有数据遍历一遍,然后存到一个扩展名为rdb的数据文件中。Bgsave为后台运行保存

redis 127.0.0.1:6379> SAVE

OK

7CONFIG RESETSTAT

充值redis服务器的统计信息,将被重置的内容如下:

Keyspace hits

Keyspace misses

Number of commands processed

Number of connections received

Number of expired keys

8Info

查看服务当前状态和版本信息。主要关心的空间使用信息used_memory_human使用内存量,vm使用率和swap使用。

举例:

redis 127.0.0.1:6379[1]> info

redis_version:2.2.12

redis_git_sha1:00000000

redis_git_dirty:0

arch_bits:64

multiplexing_api:epoll

process_id:27525

uptime_in_seconds:3085418

uptime_in_days:35

lru_clock:1807857

used_cpu_sys:79.22

used_cpu_user:186.33

used_cpu_sys_children:8.48

used_cpu_user_children:1.53

connected_clients:1

connected_slaves:0

client_longest_output_list:0

client_biggest_input_buf:0

blocked_clients:0

used_memory:83717864

used_memory_human:79.84M

used_memory_rss:127311872

mem_fragmentation_ratio:1.52

use_tcmalloc:0

loading:0

aof_enabled:0

changes_since_last_save:0

bgsave_in_progress:0

last_save_time:1318258998

bgrewriteaof_in_progress:0

total_connections_received:132983

total_commands_processed:5728570

expired_keys:0

evicted_keys:0

keyspace_hits:3588043

keyspace_misses:2140445

hash_max_zipmap_entries:512

hash_max_zipmap_value:64

pubsub_channels:0

pubsub_patterns:0

vm_enabled:0

role:master

db0:keys=664042,expires=0

db1:keys=1,expires=0

7月 07

mongodb双机主从同步初步学习

mongodb主从同步
【2011-07-06 张子萌】

mongodb的主从同步非常简单。主机启动声明自己是主机,从机启动时只需要声明自己是从机,
并填写主机的IP和端口启动即可。

数据同步实现了读写分离,在压力比较大的时候可以设置多太从机,分离读的压力。主从模式有
数据复制和Replica pairs模式模式服务器
断电或者损坏的情况下的从机会自动接管,并升级为主服务器。主机在修复后变为从机,当从机宕机
后系统会自动切换为之前的主机。在主从认证的同时也会有认证机制,用户可以创建用户信息。

a)在mongod中主从的参数如下
–master 主机模式
–slave 从机模式
–source arg 在从机上指定主机的信息
–only arg 在从机上可以指定一个数据库用于复制
–slavedelay arg 同步的延时时间,单位是秒
–autoresync 自动重新同步主服务器上的所有document。

测试环境
主从服务器存储的路径均是/data/db
主服务器IP地址为:192.168.1.51
从服务器IP地址为:192.168.1.52

b) 开始实验

需要注意两台服务器的时间要调为一致,最好设定定时同步时间。
1.分别启动主从服务器
启动主服务器使用默认端口27017
./mongod -dbpath /data/db –master
启动从服务器10002 端口
./mongod -dbpath /data/db –source 192.168.1.51:27017 –slave –port 27017 –autoresync –slavedelay 1
启动后如果从主服务器连接成功,就可以看到复制内容的信息。
当发现从服务器的数据不是最新时,就用到了autoresync和slavedelay两个参数。
启动同步系统会打出大量信息,可以使用“> /dev/null &”屏蔽日志信息。

2.测试主从同步
在主服务器新建数据库
./mongo
> use mytest
> db.mytest.save({“context”:”I am here!”})
> db.mytest.save({“context”:”hello world”})
> db.mytest.find()
可以查看到两条数据。

在从服务器上查看同步数据
./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show dbs
admin
local
test
> use mytest
switched to db testdb
> db.mytest.find()
通过查询两条数据已经同步过来。

删掉“hello world”的记录。删除只能在主机上操作。
> db.mytest.remove({“context”:”hello world”})
再次到主从台机器检查,记录已经被删掉。同步数据操作完成。

3.测试从库宕机数据丢失
从库宕机数据丢失,需要将数据从备机机同步到主机上。

首先停止主机删掉数据。(直接到数据目录下rm -rf 即可)
将备机改为主机运行,之后修好主机将主机启动为备机运行即可。

在从机上操作,停止从机进程(mongod)。删除Slave数据目录中的local.*。以主机模式启
动。待之前的主机修好后以从机模式启动即可。

7月 01

mongodb 单机的备份与恢复

【2011-06-30 张子萌】
备份与恢复是数据保存的重要技术。本次只是学习记录单机的操作。
mongodb的备份和恢复提供了两种方式。备份为bson格式和和备份为json和csv格式。

a)导出bson格式
主要用于单机小数据量的备份、快照等。存储被bson格式,bson(Binary JSON ),
是轻量级的二进制数据格式。

备份命令mongodump
参数
–help 帮助信息
-v [ –verbose ] be more verbose (include multiple times for more
verbosity e.g. -vvvvv)
-h [ –host ] arg 指定要备份的服务器ip
–port arg 指定要备份的服务器端口,需要与服务器ip一起使用,格式为ip:port
–ipv6 开启ipv6的支持,默认是关闭的
-u [ –username ] arg 用户名
-p [ –password ] arg 密码
–dbpath arg 指定连接数据库后访问数据的位置,但是不能是当前使用的目录
–directoryperdb 为每一个库建立一个目录。
-d [ –db ] arg 指定要备份的库名
-c [ –collection ] arg 指定要导出的collection
-o [ –out ] arg (=dump) 输出的目录,默认目录为执行命令的路径下创建dump目录
-q [ –query ] arg 可以json查询,有选择性的导出数据
–oplog 使用oplog
–repair 尝试修复损坏的数据库

恢复命令mongorestore
参数
–help 帮助信息
-v [ –verbose ] be more verbose (include multiple times for more
verbosity e.g. -vvvvv)
-h [ –host ] arg 指定要导入的服务器ip
–port arg 指定要导入的服务器端口,需要与服务器ip一起使用,格式为ip:port
–ipv6 开启ipv6的支持,默认是关闭的
-u [ –username ] arg 用户名
-p [ –password ] arg 密码
–dbpath arg 指定连接数据库后访问数据的位置,但是不能是当前使用的目录
–directoryperdb 为每一个库建立一个目录。
-d [ –db ] arg 指定要备份的库名
-c [ –collection ] arg 指定要导出的collection
–objcheck 插入前检测对象的合法性
–filter arg 插入前的过滤器
–drop 在导入前删除要导入的集合
–oplogReplay 恢复日志时间点

测试,首先查看要测试的数据库(mytest)文件大写
> show dbs
admin (empty)
mytest 1.953125GB
开始备份,将本地mytest库导出到tmp目录下
# mongodump -d mytest -o /tmp
导出结束耗时如下
real 0m5.412s
user 0m0.007s
sys 0m2.039s
导出后数据存为bson格式体积为577M。mytest库里存的是MP3所以导出数据库压缩的不多。

开始做恢复测试,首先删除mytest库,在导入
# mongorestore –directoryperdb -d mytest /tmp/mytest
导入结束耗时如下:
real 0m52.587s
user 0m0.514s
sys 0m1.732s

总结:导入时间大约是导出时间的10倍。

b)导出json格式
虽然导出速度快,
但是导出为json,csv可能对某些数据类型不兼容,并且不保证数据可以完整导入。
所以只简单记录一下,就不是实验了。
导出命令mongoexport
参数
-q [ –query ] arg query filter, as a JSON string
–csv export to csv instead of json
–jsonArray output to a json array rather than one object per
line

恢复命令mongoimport
参数
–ignoreBlanks 在csv,tsv文件中忽略空域
–type arg 指定导入文件的类型,默认为json,也可以是csv,tsv
–drop 导入前先删除原collection
–headerline 仅导入CSV,TSV文件的第一行作为头文件
–upsert 插入或更新已存在的对象
–upsertFields arg comma-separated fields for the query part of the
upsert. You should make sure this is indexed
–stopOnError 当导入出现错误时停止
–jsonArray 导入json array,目前每个array的限制是4M

6月 23

MongoDB的初步-安装、简单操作

网上的介绍很多所以就不废话了,先记录几个概念,直接记录关键操作。
mongodb 的官方网站http://www.mongodb.org/

MongoDB是由(database)、集合(collection)、文档对象(document)三个层次组成。与传统的
数据库对应关系如下
关系型数据库 MongoDB数据库
database database
table collection
row document
存储的数据格式是key-value对的集合,键是字符串,值可以是数据类型集合里的任意类型,包括数组和文档对象。

测试环境:CentOS 5.6 64位操作系统
将mongodb软件安装在/usr/local/mongodb
将mongodb数据放在/data/db
应该创建一个专有的操作账户。此次不麻烦了直接使用root。

A)部署
先下载mongodb到
# wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-1.8.1.tgz

进行解压缩
# tar xzvf mongodb-linux-x86_64-1.8.1.tgz

将文件移动到相应目录
# mv mongodb-linux-x86_64-1.8.1 /usr/local/mongodb

建立相应数据目录,也可以在启动时用–dbpath参数来指定数据库的路径
# mkdir -p /data/db

B)启、停数据库
进入mongodb的bin目录中
# cd /usr/local/mongodb/bin
可以看到以下命令
bsondump
mongo mongodb的客户端
mongod mongodb的服务端
mongodump mongodb的导出工具,导出为bson格式,也可用于备份、快照等。
mongoexport 把collection导出成json格式或csv格式的文件
mongofiles GridFS管理工具
mongoimport mongodb恢复工具速度快,但不保证数据完整导入
mongorestore mongodb恢复工具速度慢,但是根据mongodump导出的数据完整恢复
mongos mongodb的集群路程序
mongosniff mongodb操作捕获,类似于tcpdump,可以截获到要执行的命令
mongostat mongodb的运行信息。

启动数据库命令
# ./mongod
数据库正常启动,默认情况下客户端访问端口为27017,web访问端口为28017.
也可以使用–port参数直接设定,如果直接指定端口为4444,web访问端口将为5444,具体
信息会打出到启动信息中。常用参数还有
–fork 创建子进程
–logpath 指定日志目录,日志级别从多到少参数为从-v 到 -vvvvv
–directoryperdb 系统为每个 DB 创建一个独立子目录
–config 启动时调用配置文件,可有手动编辑配置文件
配置文件具体参数可以查询http://www.mongodb.org/display/DOCS/File+Based+Configuration
以 Daemon 方式运行# ./mongod –fork –logpath /dev/null

验证数据库是否启动正常。使用web比较方便,使用http://IP:port方式看到mongodb的
状态信息,表示启动成功。也可以使用客户端登陆,保存和查询数据,简单测试一下。这有点像
python中的字典。
# ./mongo
> db.foo.save({‘hi’:’hello word’})
> db.foo.find()
可以查到刚才保存的结果,表示数据库运行正常。客户端默认是连接本地的27017端口,如果
连接远程系统可以用 ./mongo ip:port的形式来指定IP和端口号。
到/data/db目录下,可以看到test.0、test.1、test.ns。因为mongodb采用预分配表空间机制,每个
分配文件都用0填充,第一个文件test.0为64MB,第二个文件为128MB ,依此类推,所以在32位模式运行时支持
的最大文件为2GB。每个库和索引也有对应的命名空间,命名空间的元数据都集中存在test.ns文件中。在数据插
入时每条数据都有”_id”,如果没有提供系统将自动生成Objectld作为该文档的主键。Objectid有4字节的时间戳,
3字节的机器号,2字节的进程id和3字节的自动计数组成。还有一个问题需要注意,文件删除后数据所占用的空
间不会被释放,所以不要存放经常要删除替换的文件。

关闭数据库
> use admin
> db.shutdownServer()

C)简单管理、操作命令

操作均为使用mongo连接后的操作提示符为>
命令列表 http://www.mongodb.org/display/DOCS/dbshell+Reference

切换库使用use,这个和mysql一样。切换后可以做的常用操作。
> use admin
查看帮助
> db.help()
查看当前表collection支持哪些方法
> db.dbname.help()
查看数据库运行统计信息
> db.serverStatus()
查看数据库的状态信息
> db.stats()
列出所有数据库
> show dbs
显示当前数据库
> db
打印最后出现的错误
> db.getLastError()
清除错误记录
> db.resetError()
添加用户,账户、密码、是否只读
> db.addUser(user,pwd,true)
列出用户
> show users
删除用户
> db.removeUser(“userName”)
清除错误记录
> db.resetError()
删除库
> db.dropDatabase()
将某个ip上的库同步到当前库
> db.cloneDatabase(“x.x.x.x”)
将某个ip上的数据复制到当前库
> db.copyDatabase(“test”,”x.x.x.x”)
查看数据空间大小
> db.userInfo.dataSize()

操作部分可以参照sql与mongo的对比
http://www.mongodb.org/display/DOCS/SQL+to+Mongo+Mapping+Chart
添加
> db.foo.save({‘hi’:’hello word’})
> db.foo.save({‘hi’:’nihao’})

查找
> db.foo.find({“hi”:”hello word”})

修改将”nihao”修改为”ni hao “
> db.foo.update({“hi”:”nihao”},{$set:{“hi”:”ni hao”}},false,true)

删除
> db.foo.remove({“hi”:”ni hao”})