NoSQL三--mongodb(一)

目录

一、mongodb介绍
二、mongodb安装
三、连接mongodb
四、mongodb用户管理
五、mongodb创建集合和数据管理
六、PHP的mongodb扩展
七、PHP的mongo扩展
八、mongodb副本集介绍
九、mongodb副本集搭建
十、mongodb副本集测试

一、mongodb介绍

官网www.mongodb.com, 当前最新版3.4
C++编写,基于分布式的,属于NoSQL的一种
在NoSQL中是最像关系型数据库的
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档、数组及文档数组。
关于JSON http://www.w3school.com.cn/json/index.asp
因为基于分布式,所以很容易扩展

  • MongoDB和关系型数据库对比

    image.png

  • 关系型数据库数据结构

    image.png

  • MongoDB数据结构

    image.png

二、mongodb安装

epel自带的mongodb版本为2.6,我们需要安装3.4版本
官方安装文档https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/
cd /etc/yum.repos.d/
vim mongodb-org-3.4.repo//加入如下内容
[mongodb-org-3.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
yum list |grep mongodb //可以看到mongodb相关的rpm包
yum install -y mongodb-org

#创建官方yum源
[root@minglinux-01 ~] cd /etc/yum.repos.d
[root@minglinux-01 /etc/yum.repos.d] vim mongodb-org-3.4.repo
#写入以下内容
  1 [mongodb-org-3.4]
  2 name=MongoDB Repository
  3 baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
  4 gpgcheck=1
  5 enabled=1
  6 gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc

#查看mongodb相关的rpm包
[root@minglinux-01 /etc/yum.repos.d] yum list |grep mongodb 
collectd-write_mongodb.x86_64           5.8.1-1.el7                    epel     
mongodb.x86_64                          2.6.12-6.el7                   epel     
mongodb-org.x86_64                      3.4.19-1.el7                   mongodb-org-3.4
mongodb-org-mongos.x86_64               3.4.19-1.el7                   mongodb-org-3.4
mongodb-org-server.x86_64               3.4.19-1.el7                   mongodb-org-3.4
mongodb-org-shell.x86_64                3.4.19-1.el7                   mongodb-org-3.4
mongodb-org-tools.x86_64                3.4.19-1.el7                   mongodb-org-3.4
mongodb-server.x86_64                   2.6.12-6.el7                   epel     
mongodb-test.x86_64                     2.6.12-6.el7                   epel     
nodejs-mongodb.noarch                   1.4.7-1.el7                    epel     
php-mongodb.noarch                      1.0.4-1.el7                    epel     
php-pecl-mongodb.x86_64                 1.1.10-1.el7                   epel     
poco-mongodb.x86_64                     1.6.1-3.el7                    epel     
syslog-ng-mongodb.x86_64                3.5.6-3.el7                    epel      

#安装mongodb
[root@minglinux-01 /etc/yum.repos.d] yum install -y mongodb-org

三、连接mongodb

systemctl start mongod //启动服务
在本机可以直接运行命令mongo进入到mongodb shell中
如果mongodb监听端口并不是默认的27017,则在连接的时候需要加--port 选项,例如
mongo --port 27018
连接远程mongodb,需要加--host,例如
mongo --host 127.0.0.1
如果设置了验证,则在连接的时候需要带用户名和密码
mongo -uusername -ppasswd --authenticationDatabase db //这个和MySQL挺像

[root@minglinux-01 /etc/yum.repos.d] vim /etc/mongod.conf  #配置文件
···
 27 net:
 28   port: 27017
 29   bindIp: 127.0.0.1,192.168.162.130  #限制访问的IP,增加IP用逗号隔开
#将此行注释掉则允许所有的地址访问。
···

[root@minglinux-01 /etc/yum.repos.d] systemctl start mongod  #启动mongodb
[root@minglinux-01 /etc/yum.repos.d] ps aux |grep mongod
mongod     9213 18.3  1.9 973408 36132 ?        Sl   16:39   0:01 /usr/bin/mongod -f /etc/mongod.conf
root       9242  0.0  0.0 112720   976 pts/0    S+   16:39   0:00 grep --color=auto mongod
[root@minglinux-01 /etc/yum.repos.d] netstat -lntp |grep mongod
tcp        0      0 192.168.162.130:27017   0.0.0.0:*               LISTEN      9213/mongod         
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN      9213/mongod         
[root@minglinux-01 /etc/yum.repos.d] mongo
MongoDB shell version v3.4.19
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.19
Server has startup warnings: 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
> ^C
bye
[root@minglinux-01 /etc/yum.repos.d] mongo --host 192.168.162.130 --port 27017
MongoDB shell version v3.4.19
connecting to: mongodb://192.168.162.130:27017/
MongoDB server version: 3.4.19
Server has startup warnings: 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-03-06T16:39:45.008+0800 I CONTROL  [initandlisten] 
> 

四、mongodb用户管理

use admin//需要切换到admin库
db.createUser( { user: "admin", customData: {description: "superuser"}, pwd: "admin122", roles: [ { role: "root", db: "admin" } ] } )
user指定用户,customData为说明字段,可以省略,pwd为密码,roles指定用户的角色,db指定库名
use admin //切换到admin库
db.system.users.find() //列出所有用户,需要切换到admin库
show users //查看当前库下所有的用户
db.dropUser('admin') //删除用户
若要用户生效,还需要编辑启动脚本vim /usr/lib/systemd/system/mongod.service,在OPTIONS=后面增--auth
重启服务systemctl restart mongod
mongo -u "admin" -p "admin122" --authenticationDatabase "admin"

use db1
db.createUser( { user: "test1", pwd: "123aaa", roles: [ { role: "readWrite", db: "db1" }, {role: "read", db: "db2" } ] } )
test1用户对db1库读写,对db2库只读。
之所以先use db1,表示用户在 db1 库中创建,就一定要db1库验证身份,即用户的信息跟随随数据库。比如上述 test1虽然有 db2 库的读取权限,但是一定要先在db1库进行身份验证,直接访问会提示验证失败。
use db2
db.auth("test1", "123aaa")

> use admin  #切换到admin库
switched to db admin
> db.createUser( { user: "admin", customData: {description: "superuser"}, pwd: "admin122", roles: [ { role: "root", db: "admin" } ] } )  #创建admin用户
Successfully added user: {
    "user" : "admin",
    "customData" : {
        "description" : "superuser"
    },
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}
> db.system.users.find()  #列出所有用户
{ "_id" : "admin.admin", "user" : "admin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "eNFeSQSyE3mBns9Tkf5bHQ==", "storedKey" : "kRx4Je3+de9ijoqRib9LbSbRKyc=", "serverKey" : "bICd1/FrFJjD70CvGu+KyQqhSiQ=" } }, "customData" : { "description" : "superuser" }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
> show users  #查看当前库下所有的用户
{
    "_id" : "admin.admin",
    "user" : "admin",
    "db" : "admin",
    "customData" : {
        "description" : "superuser"
    },
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}

#再创建一个用户
> db.createUser({user:"Lucci",pwd:"123123",roles:[{role:"read",db:"testdb"}]})
Successfully added user: {
    "user" : "Lucci",
    "roles" : [
        {
            "role" : "read",
            "db" : "testdb"
        }
    ]
}
#删除Lucci用户
> db.dropUser('Lucci')
true
> show users
{
    "_id" : "admin.admin",
    "user" : "admin",
    "db" : "admin",
    "customData" : {
        "description" : "superuser"
    },
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}
#若要新建用户生效,还需要编辑启动脚本
[root@minglinux-01 /etc/yum.repos.d] vim /usr/lib/systemd/system/mongod.service
···
 9 Environment="OPTIONS=--auth -f /etc/mongod.conf"  #增加--auth
···
[root@minglinux-01 /etc/yum.repos.d] systemctl restart mongod
Warning: mongod.service changed on disk. Run 'systemctl daemon-reload' to reload units.
[root@minglinux-01 /etc/yum.repos.d] systemctl daemon-reload 
[root@minglinux-01 /etc/yum.repos.d] systemctl restart mongod  #重启一哈
[root@minglinux-01 /etc/yum.repos.d] ps aux |grep mongod  
mongod    10623  2.7  2.2 973412 41824 ?        Sl   17:05   0:00 /usr/bin/mongod --auth -f /etc/mongod.conf  
root      10672  0.0  0.0 112720   980 pts/0    S+   17:06   0:00 grep --color=auto mongod
#多了--auth才能使用创建用户和密码登录

#测试
[root@minglinux-01 /etc/yum.repos.d] mongo --host 192.168.162.130 --port 27017
MongoDB shell version v3.4.19
connecting to: mongodb://192.168.162.130:27017/
MongoDB server version: 3.4.19
> use admin
switched to db admin
> show users  #报错未授权
2019-03-06T17:09:22.146+0800 E QUERY    [thread1] Error: not authorized on admin to execute command { usersInfo: 1.0 } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.getUsers@src/mongo/shell/db.js:1539:1
shellHelper.show@src/mongo/shell/utils.js:797:9
shellHelper@src/mongo/shell/utils.js:704:15
@(shellhelp2):1:1

#重新使用admin登录
[root@minglinux-01 /etc/yum.repos.d] mongo --host 192.168.162.130 --port 27017 -u "admin" -p "admin122" --authenticationDatabase "admin"
MongoDB shell version v3.4.19
connecting to: mongodb://192.168.162.130:27017/
MongoDB server version: 3.4.19
Server has startup warnings: 
2019-03-06T17:05:46.735+0800 I CONTROL  [initandlisten] 
2019-03-06T17:05:46.736+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2019-03-06T17:05:46.736+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-03-06T17:05:46.736+0800 I CONTROL  [initandlisten] 
2019-03-06T17:05:46.736+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2019-03-06T17:05:46.736+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-03-06T17:05:46.736+0800 I CONTROL  [initandlisten] 
> use admin
switched to db admin
> show users
{
    "_id" : "admin.admin",
    "user" : "admin",
    "db" : "admin",
    "customData" : {
        "description" : "superuser"
    },
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}

> use db1
switched to db db1
> db.createUser( { user: "test1", pwd: "123aaa", roles: [ { role: "readWrite", db: "db1" }, {role: "read", db: "db2" } ] } )
Successfully added user: {   #创建test1用户对db1库读写,对db2库只读
    "user" : "test1",
    "roles" : [
        {
            "role" : "readWrite",
            "db" : "db1"
        },
        {
            "role" : "read",
            "db" : "db2"
        }
    ]
}
> use db2
switched to db db2
> db.auth('test1','123aaa')
Error: Authentication failed.  #在db2中验证失败
0
> use db1
switched to db db1
> db.auth('test1','123aaa')    #test1用户在 db1 库中创建,就一定要db1库验证身份
1

  • MongoDB用户角色
    Read:允许用户读取指定数据库
    readWrite:允许用户读写指定数据库
    dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
    userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
    clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
    readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
    readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
    userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
    dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
    root:只在admin数据库中可用。超级账号,超级权限
  • MongoDB库管理
    db.version() //查看版本
    use userdb //如果库存在就切换,不存在就创建
    show dbs //查看库,此时userdb并没有出现,这是因为该库是空的,还没有任何集合,只需要创建一个集合就能看到了
    db.createCollection('clo1') //创建集合clo1,在当前库下面创建
    db.dropDatabase() //删除当前库,要想删除某个库,必须切换到那个库下
    db.stats() //查看当前库的信息
    db.serverStatus() //查看mongodb服务器的状态

五、mongodb创建集合和数据管理

db.createCollection("mycol", { capped : true, size : 6142800, max : 10000 } ) //语法:db.createCollection(name,options)
name就是集合的名字,options可选,用来配置集合的参数,参数如下
capped true/false (可选)如果为true,则启用封顶集合。封顶集合是固定大小的集合,当它达到其最大大小,会自动覆盖最早的条目。如果指定true,则也需要指定尺寸参数。
autoindexID true/false (可选)如果为true,自动创建索引_id字段的默认值是false。
size (可选)指定最大大小字节封顶集合。如果封顶如果是 true,那么你还需要指定这个字段。单位B
max (可选)指定封顶集合允许在文件的最大数量。

#MongoDB创建集合
> db.createCollection("mycol", { capped : true, size : 6142800, max : 10000 } )  
{ "ok" : 1 }
> show tables
mycol
> show collections 
mycol

#MongoDB数据管理
> db.Account.insert({AccountID:1,UserName:"abc",password:"123456"})  
WriteResult({ "nInserted" : 1 })
> show tables  #Account集合不存在,直接插入数据,则mongodb会自动创建Account集合
Account
mycol
> db.Account.insert({AccountID:2,UserName:"zxc",password:"654321"})
WriteResult({ "nInserted" : 1 })
> db.Account.update({AccountID:1},{"$set":{"Age":20}})  #更新文档
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>  db.Account.find()  #查看所有文档
{ "_id" : ObjectId("5c7fbe6fe904efb00d2a7d12"), "AccountID" : 1, "UserName" : "abc", "password" : "123456", "Age" : 20 }
{ "_id" : ObjectId("5c7fbf20e904efb00d2a7d13"), "AccountID" : 2, "UserName" : "zxc", "password" : "654321" }

#根据条件查询
>  db.Account.find({AccountID:2})   
{ "_id" : ObjectId("5c7fbf20e904efb00d2a7d13"), "AccountID" : 2, "UserName" : "zxc", "password" : "654321" }

#根据条件删除
> db.Account.remove({AccountID:1})
WriteResult({ "nRemoved" : 1 })
> db.Account.find()
{ "_id" : ObjectId("5c7fbf20e904efb00d2a7d13"), "AccountID" : 2, "UserName" : "zxc", "password" : "654321" }

#删除所有文档,即删除集合
> db.Account.drop() 
true
> show tables   
mycol    #集合Account已被删除

#进入对应的库,查看集合状态
> use db1
switched to db db1
> db.printCollectionStats()
mycol
{
    "ns" : "db1.mycol",
    "size" : 0,
    "count" : 0,
    "storageSize" : 4096,
    "capped" : true,
    "max" : 10000,
    "maxSize" : 6142976,
    "sleepCount" : 0,
    "sleepMS" : 0,
    "wiredTiger" : {
        "metadata" : {
            "formatVersion" : 1
        },
···
···

六、PHP的mongodb扩展

cd /usr/local/src/
git clone https://github.com/mongodb/mongo-php-driver
cd mongo-php-driver
git submodule update --init
/usr/local/php-fpm/bin/phpize
./configure --with-php-config=/usr/local/php-fpm/bin/php-config
make && make install
vi /usr/local/php-fpm/etc/php.ini //增加 extension = mongodb.so
/usr/local/php-fpm/bin/php -m

还可以到pecl官网上下载mongodb的扩展源码包
cd /usr/local/src/
wget https://pecl.php.net/get/mongodb-1.3.0.tgz
tar zxvf mongodb-1.3.0.tgz
cd mongodb-1.3.0
/usr/local/php-fpm/bin/phpize
./configure --with-php-config=/usr/local/php-fpm/bin/php-config
make && make install
vi /usr/local/php-fpm/etc/php.ini //增加 extension = mongodb.so
/usr/local/php-fpm/bin/php -m

[root@minglinux-01 /usr/local/src/mongodb-1.3.0] cd /usr/local/src/
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] wget https://pecl.php.net/get/mongodb-1.3.0.tgz
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] tar -zxvf mongodb-1.3.0.tgz
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] cd mongodb-1.3.0/
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] /usr/local/php/bin/phpize
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] ./configure --with-php-config=/usr/local/php-fpm/bin/php-config   #nginx是php-fpm
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] make
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] make install
Installing shared extensions:     /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] ls /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
memcache.so  mongodb.so  opcache.a  opcache.so  redis.so

#编辑/usr/local/php/etc/php.ini增加 extension = mongodb.so
[root@minglinux-01 /usr/local/src/mongodb-1.3.0] vim /usr/local/php-fpm/etc/php.ini  #注意这里是php-fpm
root@minglinux-01 ~] /usr/local/php-fpm/bin/php -m |grep mongo
mongodb   #mongodb扩展模块已加载
[root@minglinux-01 ~] /etc/init.d/php-fpm restart   #重启一下php-fpm
Gracefully shutting down php-fpm . done
Starting php-fpm  done

七、PHP的mongo扩展

到pecl官网上下载mongo的扩展源码包
cd /usr/local/src/
wget https://pecl.php.net/get/mongo-1.6.16.tgz
tar zxvf mongodb-1.6.16.tgz
cd mongodb-1.6.16
/usr/local/php-fpm/bin/phpize
./configure --with-php-config=/usr/local/php-fpm/bin/php-config
make && make install
vi /usr/local/php-fpm/etc/php.ini //增加 extension = mongo.so
/usr/local/php-fpm/bin/php -m

[root@minglinux-01 /usr/local/src/mongo-1.6.16] cd /usr/local/src/
[root@minglinux-01 /usr/local/src/mongo-1.6.16] wget https://pecl.php.net/get/mongo-1.6.16.tgz
[root@minglinux-01 /usr/local/src/mongo-1.6.16] tar -zxvf mongo-1.6.16.tgz
[root@minglinux-01 /usr/local/src/mongo-1.6.16] cd mongo-1.6.16/
[root@minglinux-01 /usr/local/src/mongo-1.6.16] /usr/local/php-fpm/bin/phpize
[root@minglinux-01 /usr/local/src/mongo-1.6.16] ./configure --with-php-config=/usr/local/php-fpm/bin/php-config
[root@minglinux-01 /usr/local/src/mongo-1.6.16] make
[root@minglinux-01 /usr/local/src/mongo-1.6.16] make install
Installing shared extensions:     /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
[root@minglinux-01 /usr/local/src/mongo-1.6.16] ls /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
memcache.so  mongodb.so  mongo.so  opcache.a  opcache.so  redis.so
[root@minglinux-01 /usr/local/src/mongo-1.6.16] vim /usr/local/php-fpm/etc/php.ini     #增加 extension = mongo.so
[root@minglinux-01 /usr/local/src/mongo-1.6.16] /usr/local/php-fpm/bin/php -m |grep mongo
mongo
mongodb
[root@minglinux-01 /usr/local/src/mongo-1.6.16] /etc/init.d/php-fpm restart 
Gracefully shutting down php-fpm . done
Starting php-fpm  done

  • 测试mongo扩展

参考文档 https://docs.mongodb.com/ecosystem/drivers/php/
http://www.runoob.com/mongodb/mongodb-php.html
vim /data/wwwroot/default/mongo.php //增加
<?php
$m = new MongoClient(); // 连接
$db =$m->test; // 获取名称为 "test" 的数据库
$collection = $db->createCollection("runoob");
echo "集合创建成功";
?>
curl localhost/mongo.php

[root@minglinux-01 /usr/local/src/mongo-1.6.16] vim /data/wwwroot/default/mongo.php 

  1 <?php
  2 $m = new MongoClient(); // 连接
  3 $db =$m->test; // 获取名称为 "test" 的数据库
  4 $collection = $db->createCollection("runoob");
  5 echo "集合创建成功";
  6 ?>

[root@minglinux-01 /usr/local/src/mongo-1.6.16] curl localhost/mongo.php
集合创建成功

#编辑启动脚本删除--auth关闭用户认证连接然后连接MongoDB查看
[root@minglinux-01 /usr/local/src/mongo-1.6.16] vim /usr/lib/systemd/system/mongod.service
[root@minglinux-01 /usr/local/src/mongo-1.6.16] systemctl daemon-reload
[root@minglinux-01 /usr/local/src/mongo-1.6.16] systemctl restart mongod
[root@minglinux-01 /usr/local/src/mongo-1.6.16] curl localhost/mongo.php
集合创建成功
[root@minglinux-01 /usr/local/src/mongo-1.6.16] mongo --host 192.168.162.130 --port 27017
···
> use test
switched to db test
> show tables
runoob    #集合创建成功

八、mongodb副本集介绍

早期版本使用master-slave,一主一从和MySQL类似,但slave在此架构中为只读,当主库宕机后,从库不能自动切换为主
目前已经淘汰master-slave模式,改为副本集,这种模式下有一个主(primary),和多个从(secondary),只读。支持给它们设置权重,当主宕掉后,权重最高的从切换为主
在此架构中还可以建立一个仲裁(arbiter)的角色,它只负责裁决,而不存储数据
在此架构中读写数据都是在主上,要想实现负载均衡的目的需要手动指定读库的目标server

  • 副本集架构图
image.png

image.png

image.png

九、mongodb副本集搭建

三台机器: 192.168.162.130(primary) 192.168.162.132(secondary) 192.168.162.128(secondary)
编辑三台机器的配置文件,更改或增加:
replication://把此行前面的#删除
##oplog大小
oplogSizeMB: 20//前面有两个空格
##复制集名称
replSetName: aminglinux//前面有两个空格
分别重启三台机器
连接主,在主上运行命令mongo
>use admin
>config={_id:"minglinux",members:[{_id:0,host:"192.168.162.130:27017"},{_id:1,host:"192.168.162.132:27017"},{_id:2,host:"192.168.162.128:27017"}]}
>rs.initiate(config)
minglinux:OTHER> rs.status() //查看状态
如果两个从上的状态为"stateStr" : "STARTUP", 则需要进行如下操作
> var config={_id:"minglinux",members:[{_id:0,host:"192.168.162.130:27017"},{_id:1,host:"192.168.162.132:27017"},{_id:2,host:"192.168.162.128:27017"}]}
>rs.reconfig(config)
此时再次查看rs.status()会发现从的状态变为SECONDARY

#首先在02和03两台机器上安装mongodb
#在192.168.162.130(primary)机器将mongodb-org-3.4.repo传到其他两台机器上
[root@minglinux-01 ~]  cat /etc/yum.repos.d/mongodb-org-3.4.repo 
[mongodb-org-3.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
[root@minglinux-01 ~] rsync -av !$ root@192.168.162.132:/etc/yum.repos.d/mongodb-org-3.4.repo 
rsync -av /etc/yum.repos.d/mongodb-org-3.4.repo root@192.168.162.132:/etc/yum.repos.d/mongodb-org-3.4.repo 
root@192.168.162.132's password: 
sending incremental file list
mongodb-org-3.4.repo
[root@minglinux-01 ~] rsync -av !$  root@192.168.162.132:/etc/yum.repos.d/mongodb-org-3.4.repo 
[root@minglinux-01 ~] rsync -av /etc/yum.repos.d/mongodb-org-3.4.repo root@192.168.162.128:/etc/yum.repos.d/mongodb-org-3.4.repo 


#192.168.162.132(secondary)安装mongodb 
[root@minglinux-02 ~] ls /etc/yum.repos.d/mongodb-org-3.4.repo 
/etc/yum.repos.d/mongodb-org-3.4.repo   #将文件中https改为http安装速度更快
[root@minglinux-02 ~] yum install -y mongodb-org

#192.168.162.128(secondary)安装mongodb
[root@minglinux-03 ~] ls /etc/yum.repos.d/mongodb-org-3.4.repo 
/etc/yum.repos.d/mongodb-org-3.4.repo   #将文件中https改为http安装速度更快
[root@minglinux-03 ~] yum install -y mongodb-org

#三台机器均按如下所示修改配置文件
[root@minglinux-01 ~] vim /etc/mongod.conf
···
 27 net:
 28   port: 27017
 29   bindIp: 127.0.0.1,192.168.162.130  #增加本机内网ip,secondary用secondary的ip
···
 36 replication:
 37   ##oplog大小
 38   oplogSizeMB: 20 #前面有两个空格 
 39   ##复制集名称
 40   replSetName: minglinux #前面有两个空格
···

[root@minglinux-01 ~] systemctl restart mongod  #重启一下服务
[root@minglinux-01 ~] ps aux |grep mongo
mongod     2655  1.8  2.6 1018984 48796 ?       Sl   15:11   0:00 /usr/bin/mongod -f /etc/mongod.conf
root       2681  0.0  0.0 112720   984 pts/1    S+   15:11   0:00 grep --color=auto mongo
##若用户认证连接没去掉则编辑启动脚本/usr/lib/systemd/system/mongod.service删除OPTIONS后面的--auth,然后执行systemctl daemon-reload
[root@minglinux-01 ~] netstat -lntp |grep mongod
tcp        0      0 192.168.162.130:27017   0.0.0.0:*               LISTEN      2025/mongod         
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN      2025/mongod   
[root@minglinux-01 ~] iptables -nvL  #三台机器都需要保证iptables没有设置规则以免阻断通信
Chain INPUT (policy ACCEPT 78862 packets, 21M bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 77332 packets, 22M bytes)
 pkts bytes target     prot opt in     out     source               destination    

 #在192.168.162.130(primary)上连接mongoDB服务
[root@minglinux-01 ~] mongo
···
···
> use admin
switched to db admin
> config={_id:"minglinux",members:[{_id:0,host:"192.168.162.130:27017"},{_id:1,host:"192.168.162.132:27017"},{_id:2,host:"192.168.162.128:27017"}]}
{
    "_id" : "minglinux",
    "members" : [
        {
            "_id" : 0,
            "host" : "192.168.162.130:27017"
        },
        {
            "_id" : 1,
            "host" : "192.168.162.132:27017"
        },
        {
            "_id" : 2,
            "host" : "192.168.162.128:27017"
        }
    ]
}
> rs.initiate(config)  #初始化,启动一个新的副本集
{ "ok" : 1 }
minglinux:OTHER> rs.status()  #查看副本集状态
{
    "set" : "minglinux",
    "date" : ISODate("2019-03-08T08:03:36.065Z"),
    "myState" : 1,
    "term" : NumberLong(1),
    "syncingTo" : "",
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1552032210, 1),
            "t" : NumberLong(1)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1552032210, 1),
            "t" : NumberLong(1)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1552032210, 1),
            "t" : NumberLong(1)
        }
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "192.168.162.130:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 2617,
            "optime" : {
                "ts" : Timestamp(1552032210, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2019-03-08T08:03:30Z"),
            "syncingTo" : "",
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "could not find member to sync from",
            "electionTime" : Timestamp(1552032179, 1),
            "electionDate" : ISODate("2019-03-08T08:02:59Z"),
            "configVersion" : 1,
            "self" : true,
            "lastHeartbeatMessage" : ""
        },
        {
            "_id" : 1,
            "name" : "192.168.162.132:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 47,
            "optime" : {
                "ts" : Timestamp(1552032210, 1),
                "t" : NumberLong(1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1552032210, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2019-03-08T08:03:30Z"),
            "optimeDurableDate" : ISODate("2019-03-08T08:03:30Z"),
            "lastHeartbeat" : ISODate("2019-03-08T08:03:35.232Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-08T08:03:34.229Z"),
            "pingMs" : NumberLong(11),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "192.168.162.130:27017",
            "syncSourceHost" : "192.168.162.130:27017",
            "syncSourceId" : 0,
            "infoMessage" : "",
            "configVersion" : 1
        },
        {
            "_id" : 2,
            "name" : "192.168.162.128:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 47,
            "optime" : {
                "ts" : Timestamp(1552032210, 1),
                "t" : NumberLong(1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1552032210, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2019-03-08T08:03:30Z"),
            "optimeDurableDate" : ISODate("2019-03-08T08:03:30Z"),
            "lastHeartbeat" : ISODate("2019-03-08T08:03:35.232Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-08T08:03:34.228Z"),
            "pingMs" : NumberLong(12),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "192.168.162.130:27017",
            "syncSourceHost" : "192.168.162.130:27017",
            "syncSourceId" : 0,
            "infoMessage" : "",
            "configVersion" : 1
        }
    ],
    "ok" : 1
}

十、mongodb副本集测试

主上建库,建集合
use mydb
db.acc.insert({AccountID:1,UserName:"123",password:"123456"})
show dbs
从上查看
show dbs
若出现错误Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" },需要执行
rs.slaveok()

#在主上建库建集合
minglinux:PRIMARY> use admin
switched to db admin
minglinux:PRIMARY> use mydb
switched to db mydb
minglinux:PRIMARY> db.acc.insert({AccountID:1,UserName:"123",password:"123456"})
WriteResult({ "nInserted" : 1 })
minglinux:PRIMARY> show dbs
admin  0.000GB
db1    0.000GB
local  0.000GB
mydb   0.000GB
test   0.000GB
minglinux:PRIMARY> use mydb
switched to db mydb
minglinux:PRIMARY> show tables
acc
#在192.168.162.132(secondary) 上连接mongodb查看
[root@minglinux-02 ~] mongo
···
···
minglinux:SECONDARY> show dbs
2019-03-09T00:56:02.077+0800 E QUERY    [thread1] Error: listDatabases failed:{
    "ok" : 0,
    "errmsg" : "not master and slaveOk=false",
    "code" : 13435,
    "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:814:19
shellHelper@src/mongo/shell/utils.js:704:15
@(shellhelp2):1:1
minglinux:SECONDARY> rs.slaveOk()
minglinux:SECONDARY> show dbs
admin  0.000GB
db1    0.000GB
local  0.000GB
mydb   0.000GB
test   0.000GB
minglinux:SECONDARY> use mydb
switched to db mydb
minglinux:SECONDARY> show tables
acc
#在192.168.162.128(secondary) 上连接mongodb查看
[root@minglinux-03 ~] mongo
···
···
minglinux:SECONDARY> show dbs
2019-03-08T17:06:30.760+0800 E QUERY    [thread1] Error: listDatabases failed:{
    "ok" : 0,
    "errmsg" : "not master and slaveOk=false",
    "code" : 13435,
    "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:814:19
shellHelper@src/mongo/shell/utils.js:704:15
@(shellhelp2):1:1
minglinux:SECONDARY> rs.slaveOk()
minglinux:SECONDARY> show dbs
admin  0.000GB
db1    0.000GB
local  0.000GB
mydb   0.000GB
test   0.000GB
minglinux:SECONDARY> use mydb
switched to db mydb
minglinux:SECONDARY> show tables
acc
  • 副本集更改权重模拟主宕机

默认三台机器权重都为1,如果任何一个权重设置为比其他的高,则该台机器马上切换为primary角色,所以我们预设三台机器的权重分别为:130:3,132:2,128:1
在主上执行
cfg = rs.conf()
cfg.members[0].priority = 3
cfg.members[1].priority = 2
cfg.members[2].priority = 1
rs.reconfig(cfg)
这样的话,第二个节点将会成为候选主节点。
主上执行 iptables -I INPUT -p tcp --dport 27017 -j DROP

# rs.config()可以查看到当前三台机器权重都为1
minglinux:PRIMARY> rs.config()

#模拟主宕机
[root@minglinux-01 ~] iptables -I INPUT -p tcp --dport 27017 -s 192.168.162.0/24 -j DROP
[root@minglinux-01 ~] mongo
···
···
minglinux:SECONDARY> rs.status()  #可以看到192.168.162.132变成了PRIMARY,因为权重都一样,PRIMARY也可能是192.168.162.132
{
    "set" : "minglinux",
    "date" : ISODate("2019-03-08T10:30:09.998Z"),
    "myState" : 2,
    "term" : NumberLong(2),
    "syncingTo" : "192.168.162.128:27017",
    "syncSourceHost" : "192.168.162.128:27017",
    "syncSourceId" : 2,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1552069813, 1),
            "t" : NumberLong(2)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1552069813, 1),
            "t" : NumberLong(2)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1552069813, 1),
            "t" : NumberLong(2)
        }
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "192.168.162.130:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 11410,
            "optime" : {
                "ts" : Timestamp(1552069813, 1),
                "t" : NumberLong(2)
            },
            "optimeDate" : ISODate("2019-03-08T18:30:13Z"),
            "syncingTo" : "192.168.162.128:27017",
            "syncSourceHost" : "192.168.162.128:27017",
            "syncSourceId" : 2,
            "infoMessage" : "syncing from: 192.168.162.128:27017",
            "configVersion" : 1,
            "self" : true,
            "lastHeartbeatMessage" : ""
        },
        {
            "_id" : 1,
            "name" : "192.168.162.132:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 27,
            "optime" : {
                "ts" : Timestamp(1552069813, 1),
                "t" : NumberLong(2)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1552069813, 1),
                "t" : NumberLong(2)
            },
            "optimeDate" : ISODate("2019-03-08T18:30:13Z"),
            "optimeDurableDate" : ISODate("2019-03-08T18:30:13Z"),
            "lastHeartbeat" : ISODate("2019-03-08T10:30:05.391Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-08T10:29:30.393Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "",
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "",
            "electionTime" : Timestamp(1552069793, 1),
            "electionDate" : ISODate("2019-03-08T18:29:53Z"),
            "configVersion" : 1
        },
        {
            "_id" : 2,
            "name" : "192.168.162.128:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 27,
            "optime" : {
                "ts" : Timestamp(1552069813, 1),
                "t" : NumberLong(2)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1552069813, 1),
                "t" : NumberLong(2)
            },
            "optimeDate" : ISODate("2019-03-08T18:30:13Z"),
            "optimeDurableDate" : ISODate("2019-03-08T18:30:13Z"),
            "lastHeartbeat" : ISODate("2019-03-08T10:30:05.391Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-08T10:29:30.406Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "192.168.162.132:27017",
            "syncSourceHost" : "192.168.162.132:27017",
            "syncSourceId" : 1,
            "infoMessage" : "",
            "configVersion" : 1
        }
    ],
    "ok" : 1
}
#给三台机器设置不同的权重
[root@minglinux-01 ~] iptables -D INPUT -p tcp --dport 27017 -s 192.168.162.0/24 -j DROP   #先将iptables规则删掉,规则删掉后PRIMAR不会自动还原,除非权重大

#在新的PRIMAR上设置权重
minglinux:PRIMARY> cfg=rs.conf()
···
minglinux:PRIMARY> cfg.members[0].priority = 3
3
minglinux:PRIMARY> cfg.members[1].priority = 2
2
minglinux:PRIMARY> cfg.members[2].priority = 1
1
minglinux:PRIMARY>  rs.reconfig(cfg)
minglinux:SECONDARY> rs.config()
{
    "_id" : "minglinux",
    "version" : 2,
    "protocolVersion" : NumberLong(1),
    "members" : [
        {
            "_id" : 0,
            "host" : "192.168.162.130:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 3,
            "tags" : {
                
            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 1,
            "host" : "192.168.162.132:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 2,
            "tags" : {
                
            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 2,
            "host" : "192.168.162.128:27017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {
                
            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }
    ],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : 60000,
        "getLastErrorModes" : {
            
        },
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("5c8221a8bbb206bd7db2b34b")
    }
}
#机器权重已修改成功
#PRIMAR变成了192.168.162.130机器,因为它的权重最高
minglinux:SECONDARY> rs.status()
{
    "set" : "minglinux",
    "date" : ISODate("2019-03-08T18:55:02.686Z"),
    "myState" : 2,
    "term" : NumberLong(3),
    "syncingTo" : "192.168.162.128:27017",
    "syncSourceHost" : "192.168.162.128:27017",
    "syncSourceId" : 2,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1552070865, 44),
            "t" : NumberLong(3)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1552070865, 45),
            "t" : NumberLong(3)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1552070865, 45),
            "t" : NumberLong(3)
        }
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "192.168.162.130:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 1046,
            "optime" : {
                "ts" : Timestamp(1552070865, 45),
                "t" : NumberLong(3)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1552070865, 45),
                "t" : NumberLong(3)
            },
            "optimeDate" : ISODate("2019-03-08T18:47:45Z"),
            "optimeDurableDate" : ISODate("2019-03-08T18:47:45Z"),
            "lastHeartbeat" : ISODate("2019-03-08T18:55:01.853Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-08T18:55:01.158Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "",
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "",
            "electionTime" : Timestamp(1552070865, 2),
            "electionDate" : ISODate("2019-03-08T18:47:45Z"),
            "configVersion" : 2
        },
        {
            "_id" : 1,
            "name" : "192.168.162.132:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 12081,
            "optime" : {
                "ts" : Timestamp(1552070865, 45),
                "t" : NumberLong(3)
            },
            "optimeDate" : ISODate("2019-03-08T18:47:45Z"),
            "syncingTo" : "192.168.162.128:27017",
            "syncSourceHost" : "192.168.162.128:27017",
            "syncSourceId" : 2,
            "infoMessage" : "",
            "configVersion" : 2,
            "self" : true,
            "lastHeartbeatMessage" : ""
        },
        {
            "_id" : 2,
            "name" : "192.168.162.128:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 10321,
            "optime" : {
                "ts" : Timestamp(1552070865, 45),
                "t" : NumberLong(3)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1552070865, 45),
                "t" : NumberLong(3)
            },
            "optimeDate" : ISODate("2019-03-08T18:47:45Z"),
            "optimeDurableDate" : ISODate("2019-03-08T18:47:45Z"),
            "lastHeartbeat" : ISODate("2019-03-08T18:55:01.787Z"),
            "lastHeartbeatRecv" : ISODate("2019-03-08T18:55:01.760Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "192.168.162.130:27017",
            "syncSourceHost" : "192.168.162.130:27017",
            "syncSourceId" : 0,
            "infoMessage" : "",
            "configVersion" : 2
        }
    ],
    "ok" : 1
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容