searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

通过golang使用MongoDB的方法介绍

2023-10-13 07:12:11
30
0

1. MongoDB介绍

1.1什么是MongoDB

MongoDB是一种非关系型数据库(NoSQL),并且是非关系型数据库里功能最丰富最像关系型数据库的。数据会优先存储在内存中,当内存不够时,只将热点数据放入内存,其他数据存在磁盘。支持数据持久化。支持排序,支持返回特定字段。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档叫做BSON类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。在MongoDB中,对于插入的格式并没有要求,字段类型可以随意变动。

比如在创建一个集合后,我们可以在这个集合加入下面的数据:

{ "name":"this is a name", "age":12 }

同样我们也可以在这个数据库插入这样的数据:

{ "name":8888, "address":"changsha" }

当插入这两个数据后,使用MongoDB Compass数据库可视化工具可以显示如下(也可以直接用mongo shell工具进行查看):

 

1.1MongoDB的高可用原理

- Journal:Journal日志是 MongoDB 的预写日志 WAL,类似 MySQL 的 redo log,然后100ms一次将Journal 日志刷盘。

- Oplog:Oplog 是用来做主从复制的,类似 MySql 里的 binlog。MongoDB 的写操作都由 Primary 节点负责,Primary 节点会在写数据时会将操作记录在 Oplog 中,Secondary 节点通过拉取 oplog 信息,回放操作实现数据同步的。

- Checkpoint:上面提到了 MongoDB 的写只写了内存和 Journal 日志 ,并没有做数据持久化,Checkpoint 就是将内存变更刷新到磁盘持久化的过程。MongoDB 会每60s一次将内存中的变更刷盘,并记录当前持久化点(checkpoint),以便数据库在重启后能快速恢复数据。

- 节点选举:MongoDB 的节点选举规则能够保证在Primary挂掉之后选取的新节点一定是集群中数据最全的一个(会去比较oplog比自己新或者相同才会投票)

 

从上面 4 点我们可以得出 MongoDB 高可用的如下结论:

  1. MongoDB 宕机重启之后可以通过 checkpoint 快速恢复上一个 60s 之前的数据。
  2. MongoDB 最后一个 checkpoint 到宕机期间的数据可以通过 Journal日志回放恢复。
  3. Journal日志因为是 100ms 刷盘一次,因此至多会丢失 100ms 的数据

 

2. MongoDB对比其他类型的数据库

Redis

读写性能最高超过MongoDB,而且支持存储list,set(集合), hash等类型。Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据。一旦内存空间不够,性能会大幅度下降,云计算的数据并不需要这些特殊类型(MongoDB也可以满足存储目前的信息了),而且redis不支持条件查询功能,没有数据分析功能。

redis应用场景:作为`Key-Value`形态的内存数据库,可以作为数据缓存(key不能重复,数据量不能太大);好友关系、用户关注、推荐模型(通过set来取交集)。

Hbase

以列相关存储架构进行数据存储的数据库,适合大批量数据的处理。从下图中可以看到HBase的行键,由主键,时间戳,列簇及列簇里的列和值组成。插入一个数据的操作相对更复杂。小数据量下各项性能HBase和MongoDB写入性能差不多,海量数据情境下HBase更优秀,但云计算系统并没有海量的数据需要使用HBase的程度。

HBase的使用场景:头条类、新闻类的的新闻、网页、图片存储在HBase之中;一些病毒公司的病毒库也是存储在HBase之中;滴滴打车的轨迹数据主要存在HBase之中。

Hbase的数据模型如下:

Row Key

Time Stamp

CF1

CF2

CF3

 

11248112

T6

 

CF2:q2=v2

CF3:q3=val3

T3

 

 

 

T2

CF1:q1=v1

 

 

向Hbase中添加数据的命令如下:

 

3. MongoDB的集群搭建方法

MongoDB集群以一个3节点的主从集群搭建为例:

3.1 需要准备的文件

1)需要准备3个文件夹用于存储3个节点的数据,假设这3个数据库要启动到不同的3个宿主机上,文件夹都可以叫做/var/mongo,每个下面再创建2个文件夹 /var/mongo/conf 和/var/mongo/db

2)准备一个KeyFile用于mongo集群间的通信,命令为sudo openssl rand -base64 512 -out ./mongodb.key 然后需要将这个文件权限改为600,并将此文件放入/var/mongo/conf/下。

3)在各/var/mongo/conf下新建一个mongo.conf文件,内容如下:

dbpath=/data/mongo/db/

auth=false

bind_ip=0.0.0.0

wiredTigerCacheSizeGB=8

replSet=testHYdb

port=27017

#keyFile=/data/mongo/conf/mongodb.key <==这句先不能加。需要等把root用户创建好,开启权限认证,重新再启动集群的时候,再添加这句。

这里需要注意:

1)在首次启动MongoDB时,需要关闭权限认证。

2)port可以根据需要来进行修改,如果节点都建到不同的宿主机上那么3个节点可以使用相同的port,如果建到相同的宿主机上那么3个mongo需要使用不同的port。

3)replSet这个是MongoDB集群的名字。

4)keyFile配置在首次启动时这句要去掉,不能写上。

3.2 启动mongo

1)使用docker命令进行启动mongo,下面的命令可以启动一个节点,一共启动3个。

docker run -it -d -p 27017:27017 --name mongodb5.0_1 -v /var/mongo/db:/data/mongo/db/ -v /var/mongo/conf/mongo.conf:/data/mongo/conf/mongo.conf mongo:5.0.10 /usr/mongo/bin/mongod -f /data/mongo/mongo.conf

 

2)使用dockr ps进行查看

 

3.3 启动集群

1) 连接任意一个docker里的MongoDB,假设host的ip为10.8.70.40。

docker exec -it 92585b /usr/mongo /bin/mongo 10.8.70.40:27017

2)进去之后输入以下命令:

var config = {_id:" testHYdb",members:[{_id:0,host:"10.8.70.40:27017"},{_id:1,host:"10.8.70.41:27018"},{_id:2,host:"10.8.70.42:27019"}]}

rs.initiate(config)

rs.secondaryOk()

然后显示testHYdb:PRIMARY 其中testHYdb是之前conf文件中设置的集群名字,后面的PRIMARY代表这个节点是主节点,从节点会显示SECONDARY。

 

3)另外两个节点的MongoDB中输入rs.secondaryOk(),这样可以开启从节点的读权限

3.4 创建用户,开启权限

1) 首先创建一个root用户,然后才可以开启集群的权限

use admin

db.createUser({user:"root",pwd:"admin123!",roles:["root"]}) #创建root用户

2)开启权限

将之前创建的mongo.conf文件中的auth改为true,将keyFile=/data/mongo/conf/mongodb.key添加到文件中。

3)重启MongoDB

3.5测试

1)使用下面的命令连接到MongoDB

docker exec -it 92585b /usr/mongo /bin/mongo 10.8.70.40:27017

2)然后切换到admin这个database中: use admin

3)使用密码切换到root用户db.auth(“root”,”$password”)  $passwod是root用户的密码

4) 测试 插入功能:

> db.createCollection("student")

{ "ok" : 1 }

> db.getCollection('student').insertOne({"name":"a5","age":"11"})

{

"acknowledged" : true,

"insertedId" : ObjectId("62c3e45df7e420ba94fe0b72")

}

5)测试 查询功能:

> db.getCollection('student').find({"age":{"$gt":10}})

{ "_id" : ObjectId("62c3e45df7e420ba94fe0b72"), "name" : "a5", "age" : 11 }

4. MongoDB的一些常用操作方法

4.1使用Mongo shell的操作方法

4.1.1帮助信息

可以通过以下命令查看各help信息:

help

db.help()

db.yourColl.help()

db.youColl.find().help()

rs.help()

4.1.2 切换/创建数据库

use yourDB  //当不存在database的时候,会自动创建;当存在database时会进行切换

4.1.3 其他常用操作数据库命令

创建一个collection

> db.createCollection("student")

{ "ok" : 1 }

插入

> db.getCollection('student').insertOne({"name":"a2test","age":"9"})

{

"acknowledged" : true,

"insertedId" : ObjectId("62c3e45df7e420ba94fe0b72")

}

删除

db.getCollection(‘student’).deleteOne({"name":"a2test"})

查找

> db.getCollection('student').find({"age":{"$gt":10}}).sort({"age":-1})

sort可以用来排序。

更新

> db.users.update({age: 9}, {$set: {name: 'changeName'}})

创建用户

> db.createUser({user:"root",pwd:"admin123!",roles:["root"]})

4.1.4 MongoDB数据备份、数据恢复

4.2版本以上的MongoDB备份和恢复数据需要另外安装一个工具包database-tools,然后使用mongodump对数据进行导出为json文件。需要恢复时新建一个空数据的MongoDB,使用mongorestore来恢复。可以使用bsondump xxxx.bson来看备份出来的数据。

具体操作如下:

备份所有库:

通过/bin/sh进去输入,记得把bak文件夹要映射到本地(可以先把备的关掉,然后备份完再启动)

mongodump -u root -p admin123! --port 27017 --authenticationDatabase admin --port 27017 -o ./bak

恢复所有库:

1.先起一个mongo,然后设置好root账户

2.通/bin/sh进去之后

datatools/bin/mongorestore -u root -p admin123! --port 27017 --authenticationDatabase admin ./bak

4.2 通过golang操作MongoDB数据库的方法

4.2.1 MongoDB的客户端连接

引入包

"go.mongodb.org/mongo-driver/bson"

"go.mongodb.org/mongo-driver/mongo"

"go.mongodb.org/mongo-driver/mongo/options"

 

客户端代码

hosts := []string{192.16.34.100:27017} //需要连接的mongo的地址和端口,如果是集群把所有节点的都写上

clientOptions := options.Client().SetHosts(hosts) //这句是设置需要连接的mongo的地址

clientOptions.SetAuth(username,password,AuthSource:"admin"}) //如果开启了权限认证,如果没开启可以不加这句

var client *mongo.Client

client, err = mongo.Connect(ctx, clientOptions)

4.2.2 MongoDB的常见操作

插入

假设有如下数据Student,类型如下,插入一条数据:

type Student struct {

Name string     `bson:"name"   mapstructure:"name"`

Age int         `bson:"age"    mapstructure:"age"`

Hobby []string  `bson:"hobby"  mapstructure:"hobby"`

Tes []Vege      `bson:"tes"    mapstructure:"tes"`

}

s := Student{Name: "tom", Age: 20}

collection := client.Database("go_db").Collection("test") //连接database

insertResult, err := collection.InsertOne(context.TODO(), s) //插入数据

查询

查找并返回特定的字段(只返回memory和id的数据,这样可以返回的减少数据量)

projection := bson.D{

    {"memory", 1},

    {"id", 1},

}

cur,err:=collection.Find(ctx,bson.D{{"key","6247569c-47bd-e3c7-c3eefd4435bf0298"}}, options.Find().SetProjection(projection))

更新

update := bson.D{{"$set", bson.D{{"likenum", 1000}, {"age", 22}}}}

ur, err := c.UpdateMany(ctx, bson.D{{"name", "a2test"}}, update)

前面为更新要匹配的条件,后面为修改的的值。可以只修改某一个字段,其他的没有修改的不会变,如果没有这个字段会进行新增。

4.2.3 MongoDB的权限添加

首先在mongo.conf里面把auth=false,关闭权限认证,然后进去之后需要先添加一个root账户db.createUser({user:"root",pwd:"admin123!",roles:["root"]}) ,之后就可以继续其他的账户添加权限了。

在admin这个database下面添加,可以给一个账户添加多个database的权限。比如db.createUser({user:"mongo1",pwd:"qwe123!",roles:[{role:"readWrite",db:"go_db"},{role:"readWrite",db:"test1"}]})。使用show users可以查看每个账户所具有的权限。

然后将auth改为true,重启数据库。用mongo命令在admin这个database下可以通过db.auth("username","password")来进行权限认证。

 

0条评论
0 / 1000