Mongodb学习(9)集群搭建以及错误处理

mongodb 这种NoSQL(非关系型数据库),有其自身的特点和有点。

本文来说一下Mongodb的三种集群方式的搭建:Replica Set / Sharding / Master-Slaver


Replica Set

       中文翻译叫做副本集

其实简单来说就是集群当中包含了多份数据,保证主节点挂掉了,备节点能继续提供数据服务,提供的前提就是数据需要和主节点一致。如下图:

       Mongodb(M)表示主节点,Mongodb(S)表示备节点,Mongodb(A)表示仲裁节点。主备节点存储数据,仲裁节点不存储数据。客户端同时连接主节点与备节点,不连接仲裁节点。

       默认设置下,主节点提供所有增删查改服务,备节点不提供任何服务,作为一个备份。但是可以通过设置使备节点提供查询服务,这样就可以减少主节点的压力,当客户端进行数据查询时,请求自动转到备节点上。这个设置叫做Read Preference Modes,同时Java客户端提供了简单的配置方式,可以不必直接对数据库进行操作

当主节点挂掉的时候,其余节点根据投票选出一个新的主节点,提供读写功能

       仲裁节点是一种特殊的节点,它本身并不存储数据,主要的作用是决定哪一个备节点在主节点挂掉之后提升为主节点,所以客户端不需要连接此节点。这里虽然只有一个备节点,但是仍然需要一个仲裁节点来提升备节点级别。

介绍完了集群方案,那么现在就开始搭建了。



1.创建数据文件夹

一般情况下,默认是把数据目录放在根节点下的, 但是这里为了省事(不用每次执行都加sudo), 因此建立在用户目录下吧

$:mkdir -p ~/data/mongodb/data/master
$:mkdir -p ~/data/mongodb/data/slaver
$:mkdir -p ~/data/mongodb/data/arbiter

这三个目录分别是主节点,备用节点, 仲裁节点

 
 

$:mkdir -p ~/data/mongodb/log/
$:touch ~/data/mongodb/log/master.log
$:touch ~/data/mongodb/log/slaver.log
$:touch ~/data/mongodb/log/artiber.log

创建log文件


好了~, 到此我们的第一步准备工作就做好了



2.建立配置文件

配置文件的内容比较多, 这里就直接写到文件中去。

配置文件说明

#dbpath:数据存放目录
#logpath:日志存放路径
#pidfilepath:进程文件,方便停止mongodb, 存贮进程号
#directoryperdb:为每一个数据库按照数据库名建立文件夹存放
#logappend:以追加的方式记录日志
#replSet:replica set的名字
#bind_ip:mongodb所绑定的ip地址
#port:mongodb进程所使用的端口号,默认为27017
#fork:以后台方式运行进程
#oplogSize:mongodb操作日志文件的最大大小。单位为Mb,默认为硬盘剩余空间的5%
#noprealloc:不预先分配存储


文件路径:~/data/mongodb/

#mast
dbpath=/home/jm/data/mongodb/data/master/
logpath=/home/jm/data/mongodb/log/master.log
pidfilepath=/home/jm/data/mongodb/master.pid
directoryperdb=true
logappend=true
replSet=testrs 
bind_ip=127.0.0.1
port=27017
fork=true
oplogSize=10000
noprealloc=true
#slaver.conf
dbpath=/home/jm/data/mongodb/data/slaver/
logpath=/home/jm/data/mongodb/log/slaver.log
pidfilepath=/home/jm/data/mongodb/slaver.pid
directoryperdb=true
logappend=true
replSet=testrs 
bind_ip=127.0.0.2
port=27017
fork=true
oplogSize=10000
noprealloc=true
#artiber.conf
dbpath=/home/jm/data/mongodb/data/arbiter/
logpath=/home/jm/data/mongodb/log/arbiter.log
pidfilepath=/home/jm/data/mongodb/arbiter.pid
directoryperdb=true
logappend=true
replSet=testrs 
bind_ip=127.0.0.3
port=27017
fork=true
oplogSize=10000
noprealloc=true


3.通过配置文件,启动mongodb

进入mongodb的安装目录下,启动


$:cd ~/mongodb-linux-x86_64-ubuntu1404-3.4.4/bin/
$:./mongod -f ~/data/mongodb/master.conf
$:./mongod -f ~/data/mongodb/slaver.conf
$:./mongod -f ~/data/mongodb/arbiter.conf


如果能够正常启动, 那么应该会有如下信息显示:

note: noprealloc may hurt performance in many applications
about to fork child process, waiting until server is ready for connections.
forked process: 9771
child process started successfully, parent exiting

这样每次启动成功就会这样显示, 进程以子进程的方式在后台运行,log也存贮在指定的目录中


4.错误处理

这里最常见的几个错误以及解决方式:

4.1 error number 1 

ERROR: child process failed, exited with error number 1


这种错误,真的是好烦人, 在网上少了老半天, 无果, 最后在一个角落里看到了一个解决方法:

报了这个 number 1 的错误, 是因为我们指定的 log路径或者是其他文件路径不正确, 造成了文件不可读

尝试用下面的命令就能看到这样的提示了:

$: ./mongod -f --repair ~/data/mongodb/master.conf 
Error reading config file: No such file or directory

解决方案其实也很简单, 一般情况下是我们的文件路径定义错误

如果是文件是放在用目录下, 一定要写清楚 绝对路径

应该是这样  /home/jm/data/mongodb/log/master.conf,   不能是~/data/mongodb/log/master.conf


4.2 error number 100


ERROR: child process failed, exited with error number 100


这算是一个Mongod 启动的一个常见错误,非法关闭的时候,lock 文件没有干掉,第二次启动的时候检查到有lock 文件的时候,就报这个错误了。

解决方法:进入 mongod 上一次启动的时候指定的 data 目录  --dbpath=~/data/mongodb/data/

删除掉该文件:

rm ~/data/mongodb/data/mongo.lock 

再使用 下面的命令修复一下,之后再次启动应该就ok了

$: ./mongod --repair


5.配置三个节点

可以通过客户端连接mongodb,也可以直接在三个节点中选择一个连接mongodb。

./mongo 127.0.0.1:27017   #ip和port是某个节点的地址  
>use admin  
cfg={ _id:"testrs", members:[ {_id:0,host:'127.0.0.1:27017',priority:2}, {_id:1,host:'127.0.0.2:27017',priority:1},   
{_id:2,host:'127.0.0.3:27017',arbiterOnly:true}] };  


cfg是可以任意的名字,当然最好不要是mongodb的关键字,conf,config都可以。最外层的_id表示replica set的名字,members里包含的是所有节点的地址以及优先级。优先级最高的即成为主节点,即这里的127.0.0.1:27017。
特别注意的是,对于仲裁节点,需要有个特别的配置——arbiterOnly:true。这个千万不能少了,不然主备模式就不能生效。
配置的生效时间根据不同的机器配置会有长有短,配置不错的话基本上十几秒内就能生效,有的配置需要一两分钟。
如果生效了,执行rs.status()命令会看到如下信息:

{
	"set" : "testrs",
	"date" : ISODate("2017-06-09T02:46:39.036Z"),
	"myState" : 1,
	"term" : NumberLong(2),
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1496976389, 1),
			"t" : NumberLong(2)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1496976389, 1),
			"t" : NumberLong(2)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1496976389, 1),
			"t" : NumberLong(2)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "127.0.0.1:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 73,
			"optime" : {
				"ts" : Timestamp(1496976389, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2017-06-09T02:46:29Z"),
			"electionTime" : Timestamp(1496976337, 1),
			"electionDate" : ISODate("2017-06-09T02:45:37Z"),
			"configVersion" : 1,
			"self" : true
		},
		{
			"_id" : 1,
			"name" : "127.0.0.2:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 61,
			"optime" : {
				"ts" : Timestamp(1496976389, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1496976389, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2017-06-09T02:46:29Z"),
			"optimeDurableDate" : ISODate("2017-06-09T02:46:29Z"),
			"lastHeartbeat" : ISODate("2017-06-09T02:46:37.701Z"),
			"lastHeartbeatRecv" : ISODate("2017-06-09T02:46:37.506Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "127.0.0.1:27017",
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "127.0.0.3:27017",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 55,
			"lastHeartbeat" : ISODate("2017-06-09T02:46:37.709Z"),
			"lastHeartbeatRecv" : ISODate("2017-06-09T02:46:38.444Z"),
			"pingMs" : NumberLong(0),
			"configVersion" : 1
		}
	],
	"ok" : 1
}

如果配置正在生效,其中会包含如下信息:

"stateStr" : "RECOVERING"  



至此, 基本的搭建工作就完成了。 下面就可以再自己调试一下

#coding:utf-8

from pymongo import MongoClient

master_client=MongoClient('127.0.0.1',27017)#连接主节点
slaver_client=MongoClient('127.0.0.2',27017)#连接从节点

#利用主节点插入数据
master_db=master_client.test
master_table=master_db.person
dict_data={'Jimy':20}
dict_list=[{'Bob':22},{'Cindy':66}]
master_table.insert_one(dict_data)
print 'insert  a  data  success'
master_table.insert(dict_list)
print 'insert   datas  success'

#利用从节点查询数据
for data in slaver_client.test.person.find():
	print data
	#结果是在从节点上查到了主节点插入的数据




插入一个启动数据库的程序

#!/usr/bin/python
#-*-coding:utf-8-*-

"""
    This file is for initiate mongodb situation
    
    When you want to save book file in file system,then you don't need sharding cluster,that the database design is:
    database:books_fs
    collections:book_detail
    fields:
        book_detail:
            book_name
            alias_name:vector
            author:vector
            book_description:string
            book_covor_image_path:string
            book_covor_image_url:string
            book_download:vector
            book_file_url:string
            book_file:string
            original_url:string
            update_time:datetime
    index:
        book_name
        alias_name
        author

    So what this do is to delete books_fs is it has existed,and create index for it.
"""

import types
from pymongo import MongoClient
from pymongo import ASCENDING, DESCENDING

DATABASE_NAME = "books_fs"
client = None
DATABASE_HOST = "localhost"
DATABASE_PORT = 27017
INDEX = {\
            #collection
            'book_detail':\
                {\
                    (('book_name',ASCENDING),('author',ASCENDING)):{'name':'book_name_author','unique':True},
                    'book_name':{'name':'book_name'},
                    'author':{'name':'author'},
                    'alias_name':{'name':'alias_name'},
                }\
        }

def drop_database(name_or_database):
    if name_or_database and client:
        client.drop_database(name_or_database)

def create_index():
    """
        create index for books_fs.book_detail
    """
    for k,v in INDEX.items():
        for key,kwargs in v.items():
            client[DATABASE_NAME][k].ensure_index(list(key) if type(key)==types.TupleType else key,**kwargs)

if __name__ == "__main__":
    client = MongoClient(DATABASE_HOST,DATABASE_PORT) 
    drop_database(DATABASE_NAME)
    create_index()







posted @ 2017-06-09 10:13  枫奇丶宛南  阅读(87)  评论(0)    收藏  举报