git 저장소를 데이터베이스 백엔드로 사용
저는 구조화된 문서 데이터베이스를 다루는 프로젝트를 하고 있습니다.저는 카테고리 트리(~1000개의 카테고리, 각 레벨에서 최대 50개의 카테고리)를 보유하고 있으며, 각 카테고리에는 수천 개(예를 들어 ~10000개)의 구조화된 문서가 포함되어 있습니다.각 문서는 구조화된 형태로 수 킬로바이트의 데이터를 제공합니다(YAML을 선호하지만, JSON이나 XML을 선호할 수도 있습니다).
이 시스템의 사용자는 다음과 같은 여러 가지 유형의 작업을 수행합니다.
- ID별로 이 문서 검색
- 문서 내부의 구조화된 속성 중 일부로 문서 검색
- 문서 편집(즉, 추가/removing/renaming/merging); 각 편집 작업은 일부 주석이 포함된 트랜잭션으로 기록되어야 합니다.
- 특정 문서에 대해 기록된 변경사항 기록 보기(문서를 누가, 언제, 왜 변경했는지, 이전 버전으로 변경했는지, 요청할 경우 이 버전으로 되돌리기 등)
이 데이터베이스: 이 제어가 왜 , (: CouchDB Mongo) 를입니다를 대한 했습니다. 그러나 이 버전 제어(역사) 문제는 저를 엉뚱한 아이디어로 유혹했습니다. 왜 제가 사용하지 말아야 하는지에 대한 것입니다.git
이 응용프로그램의 데이터베이스 백엔드로 저장소를 사용하시겠습니까?
언뜻 보면 다음과 같이 해결될 수 있습니다.
- 카테고리 = 디렉토리, 문서 = 파일
- ID로 문서 가져오기 = > 디렉토리 변경 + 작업 복사본의 파일 읽기
- 편집댓글로 문서 편집 => 다양한 사용자에 의한 커밋 만들기 + 커밋 메시지 저장
- history => 정상 git 로그 및 이전 거래 검색
- search = > 이 부분은 좀 더 까다로운 부분입니다. 제 생각에는 우리가 검색할 수 있는 열 색인과 함께 카테고리를 관계형 데이터베이스로 주기적으로 내보내야 할 것 같습니다.
이 솔루션에 다른 일반적인 함정이 있습니까?이미 그러한 백엔드를 구현하려고 시도한 사람이 있습니까(즉, RoR, node.js, Django, CakePHP 등)?이 솔루션이 성능이나 신뢰성에 영향을 미칠 가능성이 있습니까? 즉, 기존 데이터베이스 솔루션보다 성능이 훨씬 느리거나 확장성/신뢰성에 문제가 있다는 것이 입증되었습니까?서로의 저장소를 밀고 당기는 그런 서버들의 클러스터는 상당히 강력하고 신뢰성이 있어야 한다고 생각합니다.
기본적으로 이 솔루션이 효과가 있는지, 효과가 있는지, 왜 효과가 없는지 알려주십시오.
저 자신의 질문에 대답하는 것이 최선은 아니지만, 제가 결국 아이디어를 포기했기 때문에, 저는 제 경우에 효과가 있었던 근거에 대해 공유하고자 합니다.이러한 근거는 모든 경우에 적용되지 않을 수 있으므로 결정은 설계자에게 달려 있다는 점을 강조하고 싶습니다.
일반적으로 제 질문의 첫 번째 요점은 서버를 씬 클라이언트(즉, 웹 브라우저)와 동시에 사용하여 병렬로 작동하는 다중 사용자 시스템을 다루고 있다는 것입니다.이런 식으로, 저는 그들 모두를 위해 상태를 유지해야 합니다.이 접근 방식에는 여러 가지가 있지만, 리소스가 너무 까다롭거나 구현하기가 너무 복잡합니다. 따라서 모든 하드 구현 작업을 처음부터 처리해야 하는 원래의 목적이 사라집니다.
"Blunt" 접근 방식: 1명의 사용자 = 1개의 상태 = 서버가 사용자를 위해 유지 관리하는 저장소의 전체 작동 복사본.~100K의 사용자가 있는 상당히 작은 문서 데이터베이스(예: 100s MiB)를 사용한다고 해도, 모든 사용자에 대해 전체 저장소 클론을 유지하는 것은 디스크 사용량을 루프에서 실행하게 만듭니다(예: 100K의 사용자 수는 100MiB ~ 10TiB).게다가 100개의 MiB 저장소를 매번 복제한다는 것은 상당히 효과적인 방법(git 및 압축 풀기 재포장 항목을 사용하지 않음)으로 수행하더라도 몇 초의 시간이 소요되며, 이는 IMO에서 허용할 수 없습니다. 게다가 더 나쁜 것은 메인 트리에 적용하는 모든 편집을 모든 사용자의 저장소로 가져와야 한다는 것입니다. 즉, (1) 리소스 독(Resource Hog),(2) 일반적인 경우 해결되지 않은 편집 충돌이 발생할 수 있습니다.
기본적으로 디스크 사용량 측면에서 O(편집 횟수 × 데이터 × 사용자 수)만큼 나쁠 수 있으며, 이러한 디스크 사용량은 자동적으로 상당히 높은 CPU 사용량을 의미합니다.
"활성 사용자만" 접근 방식: 활성 사용자에 대해서만 작업 복사본을 유지합니다.이러한 방식으로 일반적으로 사용자별 전체 레포 클론을 저장하는 것이 아니라 다음과 같은 작업을 수행합니다.
- 사용자가 로그인할 때 저장소를 복제합니다.활성 사용자당 몇 초, 최대 100 MiB의 디스크 공간이 필요합니다.
- 사용자가 사이트에서 계속 작업을 수행하면 주어진 작업 복사본으로 작업을 수행합니다.
- 사용자가 로그아웃할 때 저장소 복제본이 분기로서 주 저장소로 다시 복사되므로 "적용되지 않은 변경사항"이 있는 경우에만 저장되므로 공간 효율성이 상당히 높습니다.
따라서 이 경우 디스크 사용량은 O(편집 횟수 × 데이터 × 활성 사용자 수)에서 최대가 되며, 이는 일반적으로 ~100입니다.총 사용자 수보다 1000배 적지만, 로그인할 때마다 사용자별 분기를 복제하고 로그아웃 또는 세션 만료 시 변경 사항을 다시 꺼내야 하므로 로그인/아웃이 더욱 복잡해지고 느려집니다(=> 트랜잭션으로 수행해야 함).절대 수치로 따지면 10 TiB의 디스크 사용량이 10으로 줄어듭니다.저 같은 경우에는 100 GiB는 받아들일 수 있겠지만, 지금도 100 MiB의 데이터베이스가 상당히 작다는 이야기를 하고 있습니다.
"희소 체크아웃" 접근법: 활성 사용자당 완전한 레포 클론 대신 "희소 체크아웃"을 하는 것은 큰 도움이 되지 않습니다.최대 10배의 디스크 공간 사용을 절약할 수 있지만 이력 관련 작업에서 CPU/디스크 부하가 훨씬 더 많이 발생하여 이러한 목적을 달성할 수 없습니다.
"Workers pool" 접근 방식: 활동적인 사람을 위해 매번 본격적인 클론 작업을 수행하는 대신, "Worker" 클론 풀을 사용할 준비가 된 상태로 유지할 수 있습니다.이렇게 하면 사용자가 로그인할 때마다 한 명의 "작업자"를 차지하여 메인 레포에서 분기를 꺼내고 로그아웃할 때 "작업자"를 해방시켜 다시 메인 레포론이 되도록 교묘하게 하드 리셋하여 다른 사용자가 로그인하는 데 사용할 준비가 됩니다.디스크 사용에는 큰 도움이 되지 않지만(활성 사용자당 전체 클론만 가능), 적어도 로그인/아웃 시간을 단축할 수 있어 훨씬 더 복잡해집니다.
즉, 의도적으로 상당히 작은 데이터베이스와 사용자 기반의 수를 계산했습니다. 100K 사용자, 1K 활성 사용자, 100MiB 총 데이터베이스 + 편집 이력, 10MiB 작업 복사본.더 중요한 크라우드 소싱 프로젝트를 살펴보면 훨씬 더 많은 수가 있습니다.
│ │ Users │ Active users │ DB+edits │ DB only │
├──────────────┼───────┼──────────────┼──────────┼─────────┤
│ MusicBrainz │ 1.2M │ 1K/week │ 30 GiB │ 20 GiB │
│ en.wikipedia │ 21.5M │ 133K/month │ 3 TiB │ 44 GiB │
│ OSM │ 1.7M │ 21K/month │ 726 GiB │ 480 GiB │
물론, 그 정도의 데이터/활동에 대해서는 이러한 접근 방식을 완전히 수용할 수 없을 것입니다.
일반적으로 웹 브라우저를 "두꺼운" 클라이언트로 사용할 수 있다면, 즉 git 작업을 실행하고 전체 체크아웃을 서버가 아닌 클라이언트 측에 거의 저장할 수 있었을 것입니다.
제가 놓친 다른 점들도 있지만, 그 점들은 첫 번째 것과 비교했을 때 그다지 나쁘지 않습니다.
- 사용자의 편집 상태가 "두꺼운" 것과 같은 패턴은 ActiveRecord, Hibernate, DataMapper, Tower 등과 같은 일반 ORM 측면에서 논란이 있습니다.
- 제가 검색해 본 것처럼, 인기 있는 프레임워크에서 git를 얻기 위한 접근 방식을 사용할 수 있는 기존의 무료 코드베이스는 전혀 없습니다.
- 어떻게든 이를 효율적으로 수행할 수 있는 서비스가 적어도 하나 있는데, 바로 github입니다. 하지만 안타깝게도, 그들의 코드베이스는 폐쇄적인 소스이며, 저는 그들이 일반적인 git 서버/repo 저장 기술을 사용하지 않는다고 의심합니다. 즉, 그들은 기본적으로 대체 "빅 데이터" git를 구현했습니다.
따라서 결론은 가능합니다. 하지만 대부분의 현재 사용 사례에서는 최적의 솔루션 근처에 있을 수 없습니다.사용자 자신의 문서-편집-역사-SQL 구현을 롤업하거나 기존 문서 데이터베이스를 사용하는 것이 더 나은 대안이 될 수 있습니다.
나의 2펜스의 가치조금 그리운 마음도 있지만...제 인큐베이팅 프로젝트 중 하나에서도 비슷한 요구사항이 있었습니다.당신의 것과 유사하게, 문서 데이터베이스(xml의 경우)와 문서 버전화가 있는 나의 주요 요구사항.협업 활용 사례가 많은 다중 사용자 시스템을 위해서였습니다.제가 선호하는 것은 대부분의 주요 요구사항을 지원하는 이용 가능한 오픈 소스 솔루션을 사용하는 것입니다.
마지막으로, 충분히 확장 가능한 방식(사용자 수, 사용량 볼륨, 스토리지 및 컴퓨팅 리소스)으로 두 가지를 모두 제공하는 제품을 찾을 수 없었습니다.저는 모든 유망한 능력과 그것을 통해 만들어낼 수 있는 (가능한) 해결책에 대해 깃에 치우쳤습니다.git 옵션을 더 많이 사용함에 따라 단일 사용자 관점에서 다중(밀리) 사용자 관점으로 이동하는 것은 명백한 과제가 되었습니다.안타깝게도 저는 당신처럼 성능 분석을 제대로 하지 못했습니다. (.. 게으른/판 2의 경우 일찍 그만두는 것이 좋습니다.) 파워 투 유!어쨌든, 저의 편향된 생각은 그 이후로 (여전히 편향된) 다음의 대안으로 바뀌었습니다: 개별 영역, 데이터베이스 및 버전 제어에서 최고의 도구 메쉬업입니다.
여전히 작업 중이지만(... 그리고 약간 무시됨), 변형된 버전은 단순히 이것입니다.
- 프론트엔드에서: (사용자 대면) 1차 레벨 스토리지(사용자 애플리케이션과 인터페이스)를 위해 데이터베이스 사용합니다.
- 백엔드에서 VCS(Version Control System)(git와 같이)를 사용하여 데이터베이스의 데이터 개체에 대한 버전 지정을 수행합니다.
본질적으로 데이터베이스에 버전 제어 플러그인을 추가하는 것과 같으며, 이 플러그인을 개발해야 할 수도 있지만 훨씬 더 쉬울 수도 있습니다.
작동 방식은 기본 다중 사용자 인터페이스 데이터 교환이 데이터베이스를 통해 이루어지는 것입니다.DBMS는 다중 사용자, 동시성, 원자 작동 등 모든 재미있고 복잡한 문제를 처리할 것입니다.백엔드에서 VCS는 단일 데이터 개체 집합(동시성 또는 다중 사용자 문제 없음)에 대해 버전 제어를 수행합니다.데이터베이스의 각 유효 트랜잭션에 대해 버전 제어는 유효하게 변경된 데이터 레코드에 대해서만 수행됩니다.
인터페이스 풀은 데이터베이스와 VCS 간의 간단한 연동 기능의 형태가 될 것입니다.설계 측면에서 단순한 접근 방식은 이벤트 기반 인터페이스로서 데이터베이스로부터의 데이터 업데이트가 버전 제어 절차를 촉발합니다(힌트: Mysql 가정, 트리거 및 sys_exec() blah blah...). 구현 복잡성 측면에서,단순하고 효과적인(예: 스크립트 작성)에서부터 복잡하고 멋진(일부 프로그래밍된 커넥터 인터페이스)에 이르기까지 다양합니다.모든 것은 당신이 그것을 얼마나 열광적으로 하고 싶은지, 그리고 당신이 얼마나 많은 땀 자본을 기꺼이 쓰는지에 달려 있습니다.간단한 스크립팅이 효과가 있을 것 같습니다.또한 최종 결과인 다양한 데이터 버전에 액세스하기 위해 VCS의 버전 태그/id/hash에서 참조하는 데이터로 데이터베이스의 클론(더 많은 데이터베이스 구조의 클론)을 채우는 것이 간단한 대안입니다. 이 비트는 인터페이스의 간단한 쿼리/변환/맵 작업이 됩니다.
아직 해결해야 할 과제와 미지의 문제가 많이 남아 있지만, 대부분의 과제의 영향과 관련성은 애플리케이션 요구사항과 사용 사례에 따라 크게 달라질 것으로 생각합니다.어떤 것들은 그냥 문제가 되지 않을 수도 있습니다.데이터 업데이트 작업 빈도가 높은 애플리케이션에 대해 데이터베이스와 VCS의 두 핵심 모듈 간 성능 일치, 데이터에 따라 깃 쪽에서 시간에 따라 리소스(스토리지 및 처리 능력)를 확장하는 문제, 사용자 증가: 안정적, 지수적 또는 최종적으로 고원의 문제 등이 있습니다.
위의 칵테일 중에서, 제가 지금 끓이고 있는 것은 이것입니다.
- VCS에 Git 사용(처음에는 2 버전 간의 변경 세트 또는 델타만 사용하기 때문에 에 적합한 오래된 CVS로 간주됨)
- mysql 사용 (내 데이터의 매우 구조화된 특성으로 인해 xml 스키마가 엄격함)
- MongoDB를 가지고 노는 것 (Git에서 사용되는 네이티브 데이터베이스 구조와 밀접하게 일치하는 NoSQL 데이터베이스를 시도하는 것)
일부 재미있는 사실 - git은 실제로 객체의 수정 간 델타만 압축 및 저장하는 등 스토리지 최적화를 위한 명확한 작업을 수행합니다. 예, git은 데이터 객체의 수정 간 변경 집합 또는 델타만 저장합니다. 어디에 적용 가능한지(언제와 어떻게 알고 있는지). 참조 : git 내부의 깊은 곳에 있는 pack files - Review of ofgit의 객체 스토리지(content-addressable file system)는 mongoDB와 같은 SQL 데이터베이스가 없는 (개념 관점에서) 두드러진 유사성을 보여줍니다.다시 말하지만, 땀 자본을 희생시키면서 두 가지를 통합할 수 있는 더 흥미로운 가능성과 성능 조정을 제공할 수 있습니다.
여기까지 하신다면, 위의 내용이 귀하의 사례에 적용될 수 있는지, 그리고 만일 그렇다면, 귀하의 마지막 종합적인 성능 분석에서 어떤 측면을 어떻게 해결할 것인지에 대해 말씀드리겠습니다.
정말 흥미로운 접근법입니다.데이터를 저장해야 한다면 매우 특정한 작업을 위해 설계된 소스 코드 저장소가 아닌 데이터베이스를 사용해야 합니다.Git을 즉시 사용할 수 있다면 괜찮지만, 그 위에 문서 저장소 계층을 구축해야 할 것입니다.따라서 기존 데이터베이스를 통해서도 구축할 수 있겠죠?그리고 여러분이 관심을 가지고 있는 내장 버전 제어라면 오픈 소스 문서 저장소 도구 중 하나를 사용하는 것이 어떨까요?선택할 수 있는 것이 많습니다.
어쨌든 Git 백엔드를 사용하기로 결정했다면 기본적으로 설명한 대로 구현하면 요구 사항에 적합할 것입니다.그러나:
1) "서로 밀고 당기는 서버들의 클러스터"를 말씀하셨습니다. - 한동안 생각해보았지만 아직도 잘 모르겠습니다.원자 연산으로 여러 저장소를 푸시/풀할 수 없습니다.저는 동시 작업 중에 약간의 병합 문제가 발생할 가능성이 있는지 궁금합니다.
2) 필요 없을 수도 있지만, 목록에 넣지 않은 문서 저장소의 분명한 기능은 접근 제어입니다.하위 모듈을 통해 일부 경로(=카테고리)에 대한 액세스를 제한할 수 있지만 문서 수준에 대한 액세스를 쉽게 허용할 수는 없을 것입니다.
위에 루비 라이브러리를 구현했습니다.libgit2
그래서 구현과 탐색이 아주 쉬워졌습니다.몇 가지 명백한 한계가 있지만, 풀 깃 툴체인을 얻을 수 있기 때문에 상당히 자유로운 시스템이기도 합니다.
이 문서에는 성능, 트레이드오프 등에 대한 몇 가지 아이디어가 포함되어 있습니다.
말씀하신 것처럼 다중 사용자 사례는 다루기가 좀 더 까다롭습니다.한 가지 가능한 해결책은 사용자별 Git 인덱스 파일을 사용하여 다음과 같은 결과를 초래하는 것입니다.
- 별도의 작업 복사본 필요 없음(디스크 사용은 변경된 파일로 제한됨)
- 시간 소모적인 준비 작업 필요 없음(사용자 세션당)
방법은 Git의 환경 변수를 도구와 결합하여 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
하지만 갈등 해결은 거의 틀림없이 여기서 가장 어려운 부분입니다.
더 쉽게 할 수 있는 아이디어는 환영합니다.
언급URL : https://stackoverflow.com/questions/20151158/using-git-repository-as-a-database-backend
'programing' 카테고리의 다른 글
최대 절전 모드 둘 다 복합 기본 키가 있는 경우 관련 없는 두 테이블에 가입 (0) | 2023.10.14 |
---|---|
안드로이드:영상 보기에서 영상을 각도만큼 회전 (0) | 2023.10.14 |
Windows에서 COM(시리얼) 포트를 나열하시겠습니까? (0) | 2023.10.14 |
애니메이션 요소 변환 회전 (0) | 2023.10.14 |
Excel 선 그래프에서 셀 무시 (0) | 2023.10.14 |