背景
目前我在一家IM相关的公司上班,老的项目聊天数据没做相关的数据缓存直接存在的mysql数据库,经常链接数过多服务假死,所以现在我们在重构整个聊天项目
业务场景数据
- 由于要持久化redis中的用户消息数据,数据量比较大,写频繁。因为MongoDB的底层实现采用内存映射机制,因此非常适合大并发量的写。
- 由于用户的消息量非常大,因此要很方便的支持水平扩展。MongoDB的对水平扩展的支持非常好,并且支持自动分片
- 因为redis和Mongodb都是Nosql其他方面的属性差不多,所以我选择了用Mongodb来储存聊天数据
业务分析
- 单聊只会缓存离线数据,拉去一条离线就会删除一条,整体数据量不大
- 群聊会缓存全部的聊天数据,对与聊天信息比较多的群会7天新建一个collection同样存30天的数据,聊天少的30天为一个collection,超过的数据会导出为文本放在minio搭建的对象存储服务器上面(eg:可以看看我其他文章,了解minio搭建已经介绍)
- 其他
mongodb 最大可以创建多少 collection ?
默认的情况下,MongoDB的每个数据库有24000左右命名空间的限制。
每个命名空间有628字节。.nsfile默认为16MB。
每个collection以及索引都算作namespace。因此如果每个collection有一个索引,
我们能创建12000个collection。
--nssize允许提升这个限制。
小心的是每个collection都会占用一些存储-很少的KB。更近一步说,任何的索引都需要至少8KB的数据空间,
也就意味着每个b-tree page大小为8KB.
如果有很多collection以及元数据经常要页输出,会导致核心的操作速度变慢。
--nssize
如果需要更多的collection,运行mongod --nssize参数。这个参数会让.ns文件更大,
支持更多的collection。注意的是 --nssize 用于最新创建数据库。如果你运行在一个存在的数据库,
希望重新定义大小,那么在运行--nssize之后,要运行db.repairDatabase()命令来调整大小。
.ns 文件最大为 2GB.
应用
collection单聊 名字我设置为single_用户id
collection群聊 名字我设置为group_群id_年月日 通过年月日就可以判断是否需要新建或者存档数据
MongoDb 集群(副本集)
mongod --nssize 500 --bind_ip 192.168.2.28 --port 27019 --dbpath /data/db_c --replSet howie/192.168.2.28:27017
mongod --nssize 500 --bind_ip 192.168.2.28 --port 27018 --dbpath /data/db_b --replSet howie/192.168.2.28:27019
mongod --nssize 500 --bind_ip 192.168.2.28 --port 27017 --dbpath /data/db_a --replSet howie/192.168.2.28:27018
随便链接到一个节点执行
config = {_id: 'howie', members: [{
"_id":1,
"host":"192.168.2.28:27017"
},{
"_id":2,
"host":"192.168.2.28:27018"
},{
"_id":3,
"host":"192.168.2.28:27019"
}]
}
rs.initiate(config)
//链接命令 mongodb://192.168.2.28:27017,192.168.2.28:27018,192.168.2.28:27019/?replicaSet=howie
简单介绍
package main
import (
"gopkg.in/mgo.v2"
"log"
"gopkg.in/mgo.v2/bson"
)
type User struct {
Id bson.ObjectId `bson:"_id"`
Name string `bson:"name"`
PassWord string `bson:"pass_word"`
Age int `bson:"age"`
}
func main() {
db, err := mgo.Dial("mongodb://192.168.2.28:27017,192.168.2.28:27018,192.168.2.28:27019/?replicaSet=howie")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
db.SetMode(mgo.Monotonic, true)
c := db.DB("howie").C("person")
//插入
/*c.Insert(&User{
Id: bson.NewObjectId(),
Name: "JK_CHENG",
PassWord: "123132",
Age: 2,
}, &User{
Id: bson.NewObjectId(),
Name: "JK_WEI",
PassWord: "qwer",
Age: 5,
}, &User{
Id: bson.NewObjectId(),
Name: "JK_HE",
PassWord: "6666",
Age: 7,
})*/
var users []User
c.Find(nil).All(&users) //查询全部数据
log.Println(users)
c.FindId(users[0].Id).All(&users) //通过ID查询
log.Println(users)
c.Find(bson.M{"name": "JK_WEI"}).All(&users) //单条件查询(=)
log.Println(users)
c.Find(bson.M{"name": bson.M{"$ne": "JK_WEI"}}).All(&users) //单条件查询(!=)
log.Println(users)
c.Find(bson.M{"age": bson.M{"$gt": 5}}).All(&users) //单条件查询(>)
log.Println(users)
c.Find(bson.M{"age": bson.M{"$gte": 5}}).All(&users) //单条件查询(>=)
log.Println(users)
c.Find(bson.M{"age": bson.M{"$lt": 5}}).All(&users) //单条件查询(<)
log.Println(users)
c.Find(bson.M{"age": bson.M{"$lte": 5}}).All(&users) //单条件查询(<=)
log.Println(users)
/*c.Find(bson.M{"name": bson.M{"$in": []string{"JK_WEI", "JK_HE"}}}).All(&users) //单条件查询(in)
log.Println(users)
c.Find(bson.M{"$or": []bson.M{bson.M{"name": "JK_WEI"}, bson.M{"age": 7}}}).All(&users) //多条件查询(or)
log.Println(users)
c.Update(bson.M{"_id": users[0].Id}, bson.M{"$set": bson.M{"name": "JK_HOWIE", "age": 61}}) //修改字段的值($set)
c.FindId(users[0].Id).All(&users)
log.Println(users)
c.Find(bson.M{"name": "JK_CHENG", "age": 66}).All(&users) //多条件查询(and)
log.Println(users)
c.Update(bson.M{"_id": users[0].Id}, bson.M{"$inc": bson.M{"age": -6,}}) //字段增加值($inc)
c.FindId(users[0].Id).All(&users)
log.Println(users)*/
//c.Update(bson.M{"_id": users[0].Id}, bson.M{"$push": bson.M{"interests": "PHP"}}) //从数组中增加一个元素($push)
c.Update(bson.M{"_id": users[0].Id}, bson.M{"$pull": bson.M{"interests": "PHP"}}) //从数组中删除一个元素($pull)
c.FindId(users[0].Id).All(&users)
log.Println(users)
c.Remove(bson.M{"name": "JK_CHENG"})//删除
}