我正在做一个处理结构化文档数据库的项目。我有一个类别树(约1000个类别,每个级别最多约50个类别),每个类别包含数千个(最多,比如说,~10000)结构化文档。每个文档都是几千字节的数据,采用某种结构化形式(我更喜欢YAML,但它也可能是JSON或XML)。
此系统的用户可以执行多种操作:
当然,传统的解决方案是使用某种文档数据库(例如CouchDB或Mongo)来解决这个问题 - 然而,这个版本控制(历史)的东西诱惑我一个疯狂的想法 - 为什么我不应该使用git
存储库作为此应用程序的数据库后端?
乍一看,它可以像这样解决:
这个解决方案还有其他常见的陷阱吗?有没有人试图实现这样的后端(即任何流行的框架--RoR,node.js,Django,CakePHP)?这个解决方案是否会对性能或可靠性产生任何影响 - 即它是否证明git比传统数据库解决方案慢得多,或者存在任何可扩展性/可靠性缺陷?我认为推送/拉取彼此存储库的这类服务器集群应该相当强大。可靠。
基本上,告诉我如果此解决方案能够正常工作,为什么它将会或不会?
答案 0 :(得分:12)
确实是一种有趣的方法。我想说,如果您需要存储数据,请使用数据库,而不是源代码存储库,它是专为特定任务而设计的。如果您可以使用Git开箱即用,那么它很好,但您可能需要在其上构建文档存储库层。所以你也可以在传统的数据库上构建它,对吗?如果它是您感兴趣的内置版本控件,为什么不使用open source document repository tools之一呢?有很多可供选择。
好吧,如果你决定去Git后端,那么如果按照你的描述实现它,基本上它可以满足你的要求。但是:
1)你提到“服务器集群互相推/拉” - 我已经考虑了一段时间,但我仍然不确定。你不能推/拉几个repos作为原子操作。我想知道在并发工作期间是否有可能出现合并混乱。
2)也许您不需要它,但是您未列出的文档存储库的明显功能是访问控制。您可以通过子模块限制对某些路径(=类别)的访问,但可能您无法轻松地在文档级别授予访问权限。
答案 1 :(得分:11)
为了减少追逐,我找不到任何提供两者的产品,其方式足够可扩展(用户数量,使用量,存储和计算资源)。我对所有有希望的git偏向git能力和(可能的)解决方案可以用它来制造。随着我更多地使用git选项,从单一用户角度转向多(毫)用户角度成为一个明显的挑战。不幸的是,我没有像你那样做大量的性能分析。 (..懒惰/退出早......对于版本2,口头禅)给你力量!无论如何,我的偏见已经转变为下一个(仍有偏见的)替代方案:在各自的领域,数据库和版本控制中最好的工具网格化。
虽然仍在进行中(......并且略微忽略),变形版本就是这样。
本质上,它相当于向数据库中添加一个版本控制插件,使用一些集成粘合剂,您可能需要开发它,但可能要容易得多。
它(应该)如何工作是主要的多用户界面数据交换是通过数据库。 DBMS将处理所有有趣和复杂的问题,如多用户,并发e,原子操作等。在后端,VCS将对一组数据对象执行版本控制(无并发或多用户问题)。对于数据库上的每个有效事务,只对已经有效更改的数据记录执行版本控制。
对于接口胶,它将采用数据库和VCS之间简单的互通功能的形式。在设计方面,简单的方法是事件驱动的接口,数据库中的数据更新触发版本控制程序(提示:假设Mysql, use of triggers and sys_exec()等等......)。在实现复杂性方面,它将范围从简单有效(例如脚本)到复杂和精彩(一些编程的连接器接口)。一切都取决于你想要用它多疯狂,以及你愿意花多少汗水资金。我认为简单的脚本编写应该是神奇的。并且为了访问最终结果,各种数据版本,一个简单的替代方案是使用VCS中版本标记/ id / hash引用的数据填充数据库的克隆(更多是数据库结构的克隆)。再次,这个位将是一个简单的查询/翻译/地图作业的接口。
仍有一些挑战和未知因素需要处理,但我认为其中大部分的影响和相关性在很大程度上取决于您的应用程序要求和用例。有些人可能最终会成为非问题。一些问题包括2个关键模块,数据库和VCS之间的性能匹配,用于具有高频数据更新活动的应用程序,git端的资源(存储和处理能力)随时间的缩放作为数据,以及用户成长:稳定,指数或最终高原
在上面的鸡尾酒中,这是我目前正在酿造的
一些有趣的事实 - git实际上确实可以清楚地优化存储,例如压缩,以及仅修改对象之间的增量存储 - 是的,git只存储数据对象修订版之间的变更集或增量,它适用于何处(它知道何时以及如何)。参考:packfiles,深入guts of Git internals - 回顾git的对象存储(内容可寻址文件系统),显示与没有SQL数据库(如mongoDB)的相似性(从概念角度来看)。同样,以牺牲汗水资本为代价,它可能为整合2和性能调整提供更有趣的可能性
如果你做到这一点,请告诉我,如果以上内容可能适用于您的情况,并假设它将如何与您上次综合性能分析中的某些方面相符合
答案 2 :(得分:2)
正如您所提到的,多用户案例处理起来有点棘手。一种可能的解决方案是使用导致
的用户特定的Git索引文件诀窍是将Git' GIT_INDEX_FILE
环境变量与手动创建Git提交的工具结合起来:
以下是解决方案概要(命令中省略了实际的SHA1哈希值):
# Initialize the index
# N.B. Use the commit hash since refs might changed during the session.
$ GIT_INDEX_FILE=user_index_file git reset --hard <starting_commit_hash>
#
# Change data and save it to `changed_file`
#
# Save changed data to the Git object database. Returns a SHA1 hash to the blob.
$ cat changed_file | git hash-object -t blob -w --stdin
da39a3ee5e6b4b0d3255bfef95601890afd80709
# Add the changed file (using the object hash) to the user-specific index
# N.B. When adding new files, --add is required
$ GIT_INDEX_FILE=user_index_file git update-index --cacheinfo 100644 <changed_data_hash> path/to/the/changed_file
# Write the index to the object db. Returns a SHA1 hash to the tree object
$ GIT_INDEX_FILE=user_index_file git write-tree
8ea32f8432d9d4fa9f9b2b602ec7ee6c90aa2d53
# Create a commit from the tree. Returns a SHA1 hash to the commit object
# N.B. Parent commit should the same commit as in the first phase.
$ echo "User X updated their data" | git commit-tree <new_tree_hash> -p <starting_commit_hash>
3f8c225835e64314f5da40e6a568ff894886b952
# Create a ref to the new commit
git update-ref refs/heads/users/user_x_change_y <new_commit_hash>
根据您的数据,您可以使用cron作业将新引用合并到master
,但冲突解决方案可以说是最难的部分。
欢迎让它变得更容易的想法。
答案 3 :(得分:2)
我在libgit2
之上实现了Ruby library,这使得这很容易实现和探索。有一些明显的局限性,但它也是一个相当自由的系统,因为你得到了完整的git工具链。
该文档包含有关性能,权衡等的一些想法。