Replies: 14 comments 3 replies
-
我不熟悉 mongodb ,但这个问题你应该去查 mongo 的文档。 |
Beta Was this translation helpful? Give feedback.
-
我查了一下,实现 bulkWrite 需要先创建一个 bulk 对象,然后执行:https://github.com/mongodb/specifications/blob/master/source/driver-bulk-update.rst 可以参考官方 js 的实现:https://github.com/mongodb/mongo/blob/master/src/mongo/shell/bulk_api.js#L914-L927 如果你按协议实现了,欢迎提交 pr 。 |
Beta Was this translation helpful? Give feedback.
-
我对mongo其实也仅仅只有一点点应用层的使用经验,今天对mongo关于bulkWrite接口做了一些简单的调研:
另外,我也简单看了skynet关于mongo的驱动实现代码lua-mongo.c,有个疑问,为啥不是直接以官方mongoc驱动为基础来封,而是另个实现了一套? |
Beta Was this translation helpful? Give feedback.
-
前面我看错了。 bulk update 是已经废弃的 api ,bulk write 属于 crud api 的一部分,应该参考: https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#insert-update-replace-delete-and-bulk-writes |
Beta Was this translation helpful? Give feedback.
-
bulk write 目前应该是用 Write protocol 见 https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/ 文档说,从 MongoDB 5.0 开始,只使用 OP_MSG 目前在 lua-mongo.c 中尚未封装。但封装很简单,就是消息头 + 消息字符串内容。 摘抄如下: /*
* OP_MSG header == 16 byte
* + 4 bytes flagBits
* + 1 byte payload type = 1
* + 1 byte payload type = 2
* + 4 byte size of payload
* == 26 bytes opcode overhead
* + X Full command document {insert: "test", writeConcern: {...}}
* + Y command identifier ("documents", "deletes", "updates") ( + \0)
*/ 即 26 字节的消息头加一个 bson 文档和若干指令字符串。封装 C 接口应该按此协议传入参数,打包成最终的数据包。 |
Beta Was this translation helpful? Give feedback.
-
我这边咨询过关于bulkWrite接口是基于server端实现还是client实现的问题,有答复说是基于服务端实现的,但他们未能提供足够说服力的证据证明是基于服务端实现的,而我这边做的调查结论都是基于客户端封装的,仍然是将请求解析成一条条原有insert,update,delete操作,然后用for循环一个个执行并拼合结果,而官方也仅仅是在shell命令层实现了js的相应封装。在mongo的github源码的cpp和h文件中也未找到bulkWrite相应函数实现。如果我调研得没错的话,我们是否也需要或值得封装一个这样的客户接口。 |
Beta Was this translation helpful? Give feedback.
-
我了研究一下 https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst CRUD API ,我是这样理解的:
不同的语言的不同 driver 做相同的事情,可能 api 叫不同的名字。为了解决这个问题,mongo 的新版本打算引入统一的 CRUD API 做所有的事情,只是提供的参数不同。所以,以后都推荐使用它。
而 CRUD Api 顺便就提供了 bulk 的功能,把多条操作打包在一起发送,并批量获取结果。有了它,driver 就不应该再自己实现 bulk api 。 关于 bulk 我是这样想的。之所以许多 driver 都提供了 bulk 打包多条指令。是因为,大多数 driver 是从 socket 层面做起,并按一问一答 Req/Resp 模式工作的。如果没拿到 server 的 resp 就不会发起下一次 Req 。这样就限制了吞吐量。为了解决这个问题,就再次设计了 bulk api ,批量提起 req 。 但是 skynet 不是这样工作的。skynet 的 IO 并不会阻塞。一条条指令发送和打包发送是没有性能区别的。你用同一个 client 对象,在不同的 coroutine 中发送,就可以做到非阻塞请求。配合 skynet.select 还能简化处理 #1602 |
Beta Was this translation helpful? Give feedback.
-
也就是说mongo是在未来的新版本中才会在服务端引入bulkWrite接口了,我之前想使用bulkWrite接口,主要是从两个方面考虑,还未涉及到性能层面上: |
Beta Was this translation helpful? Give feedback.
-
目前mongo提供的接口其实已经提供了混合型(通过upsert, multi参数)批量操作支持,目前缺少的仅是delete操作的混合请求。 |
Beta Was this translation helpful? Give feedback.
-
经研究和测试发现,目前mongo服务端已支持单请求批量插入和更新同时进行,相对于mogo官方shell客户端封装的bulkWrite来说,少了delete操作,目前skynet的mongo.lua接口中只需增加以下方法即可:
测试代码:
调用日志如下:
|
Beta Was this translation helpful? Give feedback.
-
按mongo官方shell脚本的接口形式实现了一个简单的封装版本,对性能有要求的可以按云大说的select方式进一步改进:
为啥我用不好这个代码编辑功能,所有内容会变成一行,而不用代码编辑功能,代码里的缩进格式又会被去掉。 @zhangshiqian1214 |
Beta Was this translation helpful? Give feedback.
-
附测试代码:
|
Beta Was this translation helpful? Give feedback.
-
可以看看 #1649 |
Beta Was this translation helpful? Give feedback.
-
请教skynet的mongo是否支持bulkWrite接口?我这边做了测试未找到对应方法。
我的模仿代码:
local data = {
insertOne = { document = { _id = bson.objectid(), char = "Dithras", class = "barbarian", lvl = 4 } }
}
local r = self.database:runCommand("bulkwrite", self.name, "bulks", data)
return werror(r)
返回结果如下:
{
["code"] = 59,
["codeName"] = "CommandNotFound",
["ok"] = 0.0,
["errmsg"] = "no such command: 'bulkwrite'",
}
Beta Was this translation helpful? Give feedback.
All reactions