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()