git 저장소를 데이터베이스 백엔드로 사용


119

저는 구조화 된 문서 데이터베이스를 다루는 프로젝트를하고 있습니다. 카테고리 트리 (~ 1000 개 카테고리, 각 레벨에서 최대 50 개 카테고리)가 있으며, 각 카테고리에는 수천 개 (예 : ~ 10000 개)의 구조화 된 문서가 포함되어 있습니다. 각 문서는 구조화 된 형식으로 된 몇 킬로바이트의 데이터입니다 (YAML을 선호하지만 JSON 또는 XML 일 수도 있습니다).

이 시스템의 사용자는 여러 유형의 작업을 수행합니다.

  • 이 문서를 ID로 검색
  • 내부 구조화 된 속성 중 일부로 문서 검색
  • 문서 편집 (예 : 추가 / 제거 / 이름 변경 / 병합); 각 편집 작업은 몇 가지 설명과 함께 트랜잭션으로 기록되어야합니다.
  • 특정 문서에 대해 기록 된 변경 내역보기 (문서를 누가, 언제, 왜 변경했는지보기, 이전 버전 가져 오기-요청시이 문서로 되돌리기 포함)

물론 전통적인 솔루션은이 문제에 대해 일종의 문서 데이터베이스 (예 : CouchDB 또는 Mongo)를 사용하는 것입니다. 그러나이 버전 제어 (히스토리)는 저를 거친 아이디어로 이끌었습니다. git리포지토리를 이 애플리케이션의 데이터베이스 백엔드?

언뜻 보면 다음과 같이 해결할 수 있습니다.

  • 카테고리 = 디렉토리, 문서 = 파일
  • ID로 문서 가져 오기 => 디렉토리 변경 + 작업 복사본에서 파일 읽기
  • 편집 코멘트로 문서 편집 => 다양한 사용자가 커밋 + 커밋 메시지 저장
  • 히스토리 => 일반 git 로그 및 이전 트랜잭션 검색
  • search => 약간 까다로운 부분입니다. 검색 할 수있는 열의 인덱싱을 사용하여 범주를 관계형 데이터베이스로 주기적으로 내 보내야한다고 생각합니다.

이 솔루션에 다른 일반적인 함정이 있습니까? 이미 이러한 백엔드를 구현하려고 시도한 사람이 있습니까 (예 : RoR, node.js, Django, CakePHP와 같은 인기있는 프레임 워크)? 이 솔루션이 성능이나 안정성에 어떤 영향을 미칠 수 있습니까? 즉, git이 기존 데이터베이스 솔루션보다 훨씬 느리거나 확장 성 / 신뢰성 함정이 있다는 것이 입증 되었습니까? 서로의 저장소를 푸시 / 풀링하는 서버 클러스터는 상당히 견고하고 안정적이어야한다고 생각합니다.

기본적으로 말해 경우 이 솔루션이 작동하며 그것을 것 또는하지 않을 것이다?


답변:


58

내 질문에 답하는 것이 최선의 방법은 아니지만, 궁극적으로 아이디어를 포기 했으므로 제 경우에 효과가 있었던 근거를 공유하고 싶습니다. 이 근거가 모든 경우에 적용되는 것은 아니므로 결정하는 것은 건축가에게 달려 있음을 강조하고 싶습니다.

일반적으로 내 질문이 놓친 첫 번째 요점 은 씬 클라이언트 (즉, 웹 브라우저)와 함께 내 서버를 사용하여 동시에 작동 하는 다중 사용자 시스템 을 다루고 있다는 것입니다. 이런 식으로 나는 그들 모두에 대한 상태 를 유지 해야합니다. 이것에 대한 몇 가지 접근 방식이 있지만 모두 리소스가 너무 어렵거나 구현하기 너무 복잡합니다 (따라서 처음부터 모든 어려운 구현 항목을 git에 오프로드하려는 원래 목적을 죽이는 것입니다).

  • "Blunt"접근 방식 : 사용자 1 명 = 상태 1 개 = 서버가 사용자를 위해 유지하는 저장소의 전체 작업 복사본 1 개. 100K 이하의 사용자가있는 상당히 작은 문서 데이터베이스 (예 : 100MiB)에 대해 이야기하는 경우에도 모두에 대해 전체 저장소 복제를 유지하면 디스크 사용량이 전체적으로 실행됩니다 (예 : 사용자 100K x 100MiB ~ 10TiB). . 더 나쁜 것은 IMO가 허용되지 않는 상당히 효과적인 매니어 (즉, git로 사용하지 않고 재 포장을 풀지 않음)로 수행하더라도 매번 100MiB 저장소를 복제하는 데 몇 초가 걸린다는 것입니다. 더 나쁜 것은 우리가 메인 트리에 적용하는 모든 편집 내용을 모든 사용자의 저장소로 가져와야합니다. 즉, (1) 리소스 돼지, (2) 일반적으로 해결되지 않은 편집 충돌이 발생할 수 있습니다.

    기본적으로 디스크 사용량 측면에서 O (편집 횟수 × 데이터 × 사용자 수)만큼 나쁠 수 있으며 이러한 디스크 사용량은 자동으로 CPU 사용량이 매우 높다는 것을 의미합니다.

  • "활성 사용자 만"접근 방식 : 활성 사용자에 대해서만 작업 복사본을 유지합니다. 이렇게하면 일반적으로 사용자 당 전체 저장소 클론이 아닌 다음을 저장합니다.

    • 사용자가 로그인하면 저장소를 복제합니다. 활성 사용자 당 몇 초와 ~ 100MiB의 디스크 공간이 필요합니다.
    • 사용자가 사이트에서 계속 작업하면 주어진 작업 복사본으로 작업합니다.
    • 사용자가 로그 아웃하면 저장소 복제본이 분기로 기본 저장소에 다시 복사되므로 "적용되지 않은 변경 사항"만 저장됩니다 (있는 경우). 이는 상당히 공간 효율적입니다.

    따라서이 경우 디스크 사용량은 최대 O (편집 수 × 데이터 × 활성 사용자 수)로, 일반적으로 총 사용자 수보다 ~ 100..1000 배 적지 만 로그인 / 로그 아웃이 더 복잡하고 느려집니다. , 모든 로그인에서 사용자 별 브랜치를 복제하고 로그 아웃 또는 세션 만료시 이러한 변경 사항을 다시 가져 오는 작업이 포함되기 때문에 (트랜잭션 방식으로 수행해야 함 => 또 다른 복잡성 계층이 추가됨). 절대 숫자로 보면 10TiB의 디스크 사용량이 제 경우에는 10..100GiB로 떨어집니다. 이는 허용 가능할 수도 있지만 지금은 100MiB의 상당히 작은 데이터베이스에 대해 이야기하고 있습니다.

  • "스파 스 체크 아웃"접근 방식 : 활성 사용자별로 본격적인 리포지토리 복제 대신 "스파 스 체크 아웃"을하는 것은 많은 도움이되지 않습니다. 디스크 공간 사용량을 최대 10 배까지 절약 할 수 있지만 기록과 관련된 작업에 대한 CPU / 디스크 부하가 훨씬 높아져 목적이 죽습니다.

  • "작업자 풀"접근 방식 : 활동적인 사람을 위해 매번 본격적인 클론을 수행하는 대신 사용할 준비가 된 "작업자"클론 풀을 유지할 수 있습니다. 이렇게하면 사용자가 로그인 할 때마다 한 명의 "작업자"를 차지하여 주 저장소에서 분기를 가져오고 로그 아웃 할 때 "작업자"를 해제하여 영리한 git 하드 재설정을 수행하여 다시 다른 사용자가 로그인하는 데 사용할 준비가 된 기본 저장소 복제. 디스크 사용에 큰 도움이되지는 않지만 (여전히 높음-활성 사용자 당 전체 복제 만 가능) 최소한 로그인 / 로그 아웃 속도가 빨라집니다. 훨씬 더 복잡합니다.

즉, 의도적으로 매우 작은 데이터베이스 및 사용자 기반 수를 계산했습니다. 사용자 10 만 명, 활성 사용자 1 천 명, 총 데이터베이스 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 구현으로 롤업하거나 기존 문서 데이터베이스를 사용하는 것이 아마도 더 나은 대안이 될 것입니다.


16
아마도 파티에 조금 늦었지만 비슷한 요구 사항이 있었고 실제로 git-route로 내려갔습니다. git 내부를 살펴본 후 작동하는 방법을 찾았습니다. 아이디어는 베어 저장소로 작업하는 것입니다. 몇 가지 단점이 있지만 실행 가능하다고 생각합니다. 나는 당신이 확인하고 싶은 게시물에 모든 것을 썼다. (만약 흥미를 위해) : kenneth-truyers.net/2016/10/13/git-nosql-database
Kenneth

이 작업을 수행하지 않는 또 다른 이유는 쿼리 기능입니다. 문서 저장소는 종종 문서를 색인화하여 문서 내에서 쉽게 검색 할 수 있도록합니다. 이것은 git에서는 간단하지 않습니다.
FrankyHollywood 2011

12

참으로 흥미로운 접근 방식입니다. 데이터를 저장해야한다면 매우 구체적인 작업을 위해 설계된 소스 코드 저장소가 아닌 데이터베이스를 사용하십시오. 기본적으로 Git을 사용할 수 있다면 괜찮지 만 그 위에 문서 저장소 레이어를 구축해야 할 수도 있습니다. 따라서 기존 데이터베이스 위에 구축 할 수도 있습니다. 관심이있는 기본 제공 버전 제어 인 경우 오픈 소스 문서 저장소 도구 중 하나를 사용 하는 것이 어떻습니까? 선택할 수있는 것이 많습니다.

글쎄, 어쨌든 Git 백엔드로 가기로 결정했다면 기본적으로 설명한대로 구현하면 기본적으로 요구 사항에 맞을 것입니다. 그러나:

1) "서로 밀고 당기는 서버 클러스터"에 대해 언급하셨습니다. 한동안 생각해 보았지만 여전히 잘 모르겠습니다. 원자 적 작업으로 여러 저장소를 푸시 / 풀 수 없습니다. 동시 작업 중에 병합이 엉망이 될 가능성이 있는지 궁금합니다.

2) 필요하지 않을 수도 있지만 나열하지 않은 문서 저장소의 명백한 기능은 액세스 제어입니다. 하위 모듈을 통해 일부 경로 (= 카테고리)에 대한 액세스를 제한 할 수 있지만 문서 수준에서 쉽게 액세스 권한을 부여 할 수는 없습니다.


11

내 2 펜스 가치. 약간 그리움이긴하지만 ...... 저도 인큐베이션 프로젝트에서 비슷한 요구 사항이있었습니다. 당신과 마찬가지로 문서 버전 관리와 함께 문서 데이터베이스 (내 경우 xml)가있는 내 주요 요구 사항. 협업 사용 사례가 많은 다중 사용자 시스템을위한 것입니다. 필자는 대부분의 주요 요구 사항을 지원하는 사용 가능한 오픈 소스 솔루션을 사용하는 것을 선호했습니다.

추격하기 위해 충분히 확장 가능한 방식 (사용자 수, 사용량, 스토리지 및 컴퓨팅 리소스)으로 두 가지를 모두 제공하는 제품을 찾을 수 없었습니다. 모든 유망한 기능에 대해 git에 편향되었습니다. (아마도) 그것으로 만들 수있는 해결책. git 옵션을 더 많이 사용하면서 단일 사용자 관점에서 다중 (밀리) 사용자 관점으로 이동하는 것이 분명한 도전이되었습니다. 불행히도 나는 당신처럼 상당한 성능 분석을하지 못했습니다. (.. lazy / quit early .... for version 2, mantra) Power to you !. 어쨌든, 내 편향된 아이디어는 다음 (여전히 편향된) 대안으로 변형되었습니다. 즉, 별도의 영역, 데이터베이스 및 버전 제어에서 가장 뛰어난 도구의 집합체입니다.

아직 작업이 진행 중이지만 (약간 무시 됨) 변형 된 버전은 간단합니다.

  • 프런트 엔드에서 : (userfacing) 첫 번째 수준 저장소에 데이터베이스 사용 (사용자 응용 프로그램과의 인터페이스)
  • 백엔드에서 버전 제어 시스템 (VCS) (예 : git)을 사용하여 데이터베이스에서 데이터 객체의 버전 관리를 수행합니다.

본질적으로 데이터베이스에 버전 제어 플러그인을 추가하고 일부 통합 접착제를 추가하는 것과 같습니다. 개발해야 할 수도 있지만 훨씬 쉬울 수도 있습니다.

작동 방식 (으로 가정)은 기본 다중 사용자 인터페이스 데이터 교환이 데이터베이스를 통해 이루어지는 것입니다. DBMS는 다중 사용자, 동시성 e, 원자 적 작업 등과 같은 모든 재미 있고 복잡한 문제를 처리합니다. 백엔드에서 VCS는 단일 데이터 개체 집합에 대해 버전 제어를 수행합니다 (동시성 또는 다중 사용자 문제 없음). 데이터베이스의 각 유효 트랜잭션에 대해 버전 제어는 효과적으로 변경되었을 데이터 레코드에 대해서만 수행됩니다.

인터페이싱 글루는 데이터베이스와 VCS 간의 단순한 연동 기능의 형태가 될 것입니다. 디자인 측면에서 간단한 접근 방식은 데이터베이스의 데이터 업데이트가 버전 제어 절차를 트리거하는 이벤트 기반 인터페이스 (힌트 : Mysql 가정 , 트리거 및 sys_exec () 사용)입니다. blah blah ...). 구현 복잡성 측면에서 간단하고 효과적인 것 (예 : 스크립팅)에서 복잡하고 멋진 것 (일부 프로그래밍 된 커넥터 인터페이스)에 이르기까지 다양합니다. 모든 것은 당신이 얼마나 미친 듯이 가고 싶은지, 그리고 얼마나 많은 땀 자본을 기꺼이 지출 하느냐에 달려 있습니다. 간단한 스크립팅이 마법을 수행해야한다고 생각합니다. 최종 결과 인 다양한 데이터 버전에 액세스하기 위해 간단한 대안은 VCS의 버전 태그 / ID / 해시에서 참조하는 데이터로 데이터베이스의 복제본 (데이터베이스 구조의 복제본에 더 가깝습니다)을 채우는 것입니다. 다시이 비트는 인터페이스의 간단한 쿼리 / 번역 / 맵 작업입니다.

여전히 처리해야 할 몇 가지 문제와 알려지지 않은 사항이 있지만 이러한 영향과 관련성은 대부분 애플리케이션 요구 사항과 사용 사례에 따라 달라집니다. 일부는 문제가되지 않을 수도 있습니다. 몇 가지 문제에는 두 가지 주요 모듈 인 데이터베이스와 VCS 간의 성능 일치, 빈도가 높은 데이터 업데이트 활동이있는 애플리케이션, git 측에서 시간에 따른 리소스 확장 (스토리지 및 처리 능력) 및 사용자가 포함됩니다. 성장 : 꾸준한, 지수 적 또는 결국 정체

위의 칵테일 중 제가 현재 양조하고있는 것은 다음과 같습니다.

  • VCS에 Git 사용 (처음에는 두 버전 사이의 변경 세트 또는 델타 만 사용하기 때문에 처음에는 좋은 오래된 CVS로 간주 됨)
  • mysql 사용 (내 데이터의 고도로 구조화 된 특성으로 인해 엄격한 xml 스키마가있는 xml)
  • MongoDB를 가지고 놀기 (git에서 사용되는 기본 데이터베이스 구조와 거의 일치하는 NoSQl 데이터베이스를 시도하기 위해)

몇 가지 재미있는 사실-git은 실제로 압축 및 객체 개정 사이의 델타 만 저장하는 것과 같은 저장소를 최적화하기 위해 명확한 작업을 수행합니다. 예, git은 데이터 객체 개정 사이의 변경 집합 또는 델타 만 저장합니다. 언제 어떻게) . 참조 : Git 내부의 내부 에있는 packfiles -git의 개체 저장소 (컨텐츠 주소 지정 파일 시스템) 검토는 mongoDB와 같은 noSQL 데이터베이스와의 놀라운 유사점 (개념 관점에서)을 보여줍니다. 다시 말하지만, 땀 자본을 희생시키면서 2를 통합하고 성능을 조정하는 데 더 흥미로운 가능성을 제공 할 수 있습니다.

여기까지왔다면 위의 내용이 귀하의 경우에 해당 될 수 있는지, 그리고 그것이 될 것이라고 가정하면 마지막 포괄적 인 성능 분석의 일부 측면에 제곱하는 방법을 알려주십시오.


4

나는 구현 루비 라이브러리 의 상단 libgit2이 아주 쉽게 구현하고 탐구 할 수있는합니다. 몇 가지 명백한 제한 사항이 있지만 전체 git 도구 모음을 사용하기 때문에 상당히 해방적인 시스템이기도합니다.

설명서에는 성능, 장단점 등에 대한 몇 가지 아이디어가 포함되어 있습니다.


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>

데이터에 따라 크론 작업을 사용하여 새 참조를 병합 할 수 master있지만 충돌 해결이 여기서 가장 어려운 부분입니다.

더 쉽게 만들 수있는 아이디어를 환영합니다.


수동 충돌 해결을위한 트랜잭션 및 UI에 대한 완전한 개념을 원하지 않는 한 일반적으로 아무데도 이끄 지 않는 접근 방식입니다. 충돌에 대한 일반적인 아이디어는 커밋시 사용자가 문제를 바로 해결하도록하는 것입니다 (예 : "죄송합니다. 다른 사람이 편집중인 문서를 편집했습니다-> 편집 내용과 편집 내용을보고 병합하십시오"). 두 명의 사용자가 성공적으로 커밋하도록 허용 한 다음 비동기 cronjob에서 문제가 발생했음을 알면 일반적으로 문제를 해결할 수있는 사람이 없습니다.
GreyCat 2016-10-20
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.