클라이언트-서버의 동기화 패턴/알고리즘?
-
03-07-2019 - |
문제
나는 느낌이 있어야한다는 클라이언트-서버의 동기화 패턴은 거기에있다.하지만 나는 완전히 실패했을 구글됩니다.
상황은 매우 간단하다-서버가 중앙 노드,여러 클라이언트에 연결하고 조작하는 동일한 데이터이다.데이터 분할할 수 있습에서는 원자,분쟁의 경우,어떤 서버에서,우선 순위(을 받고 피하기 위해 사용자로 분쟁 해결).부분적 동기화가 선호하는 인한 잠재적으로 다량의 데이터입니다.
이 있는 패턴/모범 사례에 대한 이러한 상황,또는 알지 못하는 경우의 모든 것을 당신의 방법?
방법은 아래 나는 지금 생각하는 그것을 해결하기:데이터,수정하는 저널이 개최됩니다,모든 트랜잭션 타임 스탬프가 있습니다.면 클라이언트가 연결을 받는 모든 변경 사항부터 마지막 체크,통합된 형태(서버가 목록을 통해하고 제거하는 추가는 다음에 의해 삭제,병합 업데이트에 대한 각 원자,etc.).Et voila,우리는 최신 상태입니다.
대안이 유지 될 것이라고 수정 날짜에 대한 각각의 레코드를 수행하는 대신 데이터를 삭제하고,그 표시로 삭제됩니다.
어떤 생각?
해결책
분산 변경 관리가 어떻게 작동하는지 살펴 봐야합니다. SVN, CVS 및 DELTAS 작업을 관리하는 기타 리포지토리를보십시오.
몇 가지 사용 사례가 있습니다.
변경 사항을 동기화합니다. 변경 로그 (또는 델타 기록) 접근 방식은 이에 적합합니다. 고객은 델타를 서버로 보냅니다. 서버는 델타를 클라이언트에 통합하고 배포합니다. 이것은 일반적인 경우입니다. 데이터베이스는 이것을 "거래 복제"라고합니다.
클라이언트는 동기화를 잃었습니다. 백업/복원을 통해 또는 버그로 인해. 이 경우 클라이언트는 델타를 통과하지 않고 서버에서 현재 상태를 가져와야합니다. 이것은 마스터에서 세부 사항까지, 델타 및 성능이 저주됩니다. 일회성입니다. 클라이언트가 깨졌습니다. 이것을 최적화하려고 시도하지 말고 신뢰할 수있는 사본 만 구현하십시오.
고객은 의심 스럽다. 이 경우 클라이언트가 최신 상태이고 델타가 필요한지 확인하기 위해 클라이언트를 서버와 비교해야합니다.
모든 변경 사항을 순차적으로 번호를 매기는 데이터베이스 (및 SVN) 설계 패턴을 따라야합니다. 이렇게하면 고객이 동기화를 시도하기 전에 사소한 요청을 할 수 있습니다 ( "어떤 개정판이 있어야합니까?"). 그럼에도 불구하고 쿼리 ( "2149 이후의 모든 델타")는 클라이언트와 서버가 처리하기에 즐겁게 간단합니다.
다른 팁
팀의 일환으로 데이터 동기화와 관련된 많은 프로젝트를 수행 했으므로이 질문에 대답 할 수 있어야합니다.
데이터 동기화는 상당히 광범위한 개념이며 논의하기에는 너무 많은 것이 있습니다. 위와 단점으로 다양한 접근 방식을 다룹니다. 다음은 동기 / 비동기식, 클라이언트 / 서버 / 피어 투 피어의 두 가지 관점을 기반으로 가능한 분류 중 하나입니다. 구현 동기화는 이러한 요소, 데이터 모델 복잡성, 전송 및 저장된 데이터 양 및 기타 요구 사항에 크게 의존합니다. 따라서 각각의 경우 각각의 경우 선택은 앱 요구 사항을 충족하는 가장 간단한 구현에 유리해야합니다.
기존의 상용 솔루션을 검토 한 결과, 동기화 대상 대상의 세분성에서 다른 여러 주요 클래스의 동기화 클래스를 묘사 할 수 있습니다.
- 전체 문서 또는 데이터베이스 동기화는 Dropbox, Google Drive 또는 Yandex.disk와 같은 클라우드 기반 응용 프로그램에 사용됩니다. 사용자가 파일을 편집하고 저장하면 새 파일 버전이 클라우드에 완전히 업로드되어 이전 사본을 덮어 씁니다. 충돌이 발생하면 두 파일 버전 모두 저장되어 사용자가 더 관련성이 높은 버전을 선택할 수 있습니다.
- 키 값 쌍의 동기화는 변수가 원자 인 것으로 간주되는 간단한 데이터 구조를 가진 앱에서 사용할 수 있으며, 즉 논리적 구성 요소로 나뉘 지 않습니다. 이 옵션은 값과 문서를 완전히 덮어 쓸 수 있으므로 전체 문서의 동기화와 유사합니다. 그러나 사용자 관점에서 문서는 많은 부분으로 구성된 복잡한 객체이지만 키 값 쌍은 짧은 문자열 또는 숫자입니다. 따라서이 경우 우리는 마지막으로 변경 한 경우 더 관련성이 높은 가치를 고려할 때보다 간단한 갈등 해결 전략을 사용할 수 있습니다.
- 트리 또는 그래프로 구성된 데이터의 동기화는 데이터의 양이 모든 업데이트시 데이터베이스를 전체적으로 보낼 수있을 정도로 큰 정교한 응용 프로그램에서 사용됩니다. 이 경우 개별 대상, 필드 또는 관계 수준에서 갈등을 해결해야합니다. 우리는 주로이 옵션에 중점을 둡니다.
따라서 우리는이 기사에 대한 지식을 가져 왔습니다.이 기사에 관심이있는 모든 사람들에게 매우 유용 할 수 있다고 생각합니다.http://blog.denivip.ru/index.php/2014/04/data-syncing-in-core-data--os-apps/?lang=en)
당신이 정말로 필요한 것은 변환 운영 (OT).이용에 대한 충돌하는 경우가 많습니다.
이것은 여전히 활성 영역의 연구가 있지만 구현의 다양한 OT 알고리즘니다.가 참여 등을 위한 연구의 수 년 동안 지금,그래서 알려주는 경우 이 경로에 관심있고 행복한 당신을 넣어에 관련된 리소스입니다.
문제는 명확하지 않지만 나는 조사 할 것이다 낙관적 잠금 내가 당신이라면. 서버가 각 레코드에 대해 반환하는 시퀀스 번호로 구현할 수 있습니다. 클라이언트가 레코드를 다시 저장하려고하면 서버에서받은 시퀀스 번호가 포함됩니다. 시퀀스 번호가 업데이트가 수신 된 시점에 데이터베이스의 내용과 일치하면 업데이트가 허용되고 시퀀스 번호가 증가합니다. 시퀀스 번호가 일치하지 않으면 업데이트가 허용되지 않습니다.
나는 약 8 년 전에 앱을 위해 이와 같은 시스템을 구축했으며 앱 사용이 증가함에 따라 진화 한 몇 가지 방법을 공유 할 수 있습니다.
나는 모든 장치에서 "히스토리"테이블로 모든 변경 (삽입, 업데이트 또는 삭제)을 기록하여 시작했습니다. 예를 들어 누군가가 "연락처"테이블에서 전화 번호를 변경하면 시스템이 Contact.phone 필드를 편집하고 Action = Update, Field = Phone, Record = [Contact ID]를 사용하여 히스토리 레코드를 추가합니다. value = [새 전화 번호]. 그런 다음 장치가 동기화 될 때마다 마지막 동기화 이후 이력 항목을 다운로드하여 로컬 데이터베이스에 적용합니다. 이것은 위에서 설명한 "트랜잭션 복제"패턴처럼 들립니다.
한 가지 문제는 다른 장치에서 항목을 만들 수있을 때 ID를 고유하게 유지하는 것입니다. 이 작업을 시작할 때 UUID에 대해 알지 못했기 때문에 자동 증가 ID를 사용하고 중앙 서버에서 실행되는 복잡한 코드를 사용하여 장치에서 업로드 된 새 ID를 확인하고 충돌이있는 경우 고유 한 ID로 변경했습니다. 소스 장치에 로컬 데이터베이스에서 ID를 변경하도록 지시하십시오. 새 레코드의 ID를 변경하는 것만으로도 나쁘지는 않았지만, 예를 들어 연락처 테이블의 새 항목을 작성하고 이벤트 테이블에 새 관련 항목을 만들면 이제 필요한 외래 키가 있습니다. 확인 및 업데이트.
결국 나는 UUIDS가 이것을 피할 수 있다는 것을 알게되었지만, 그때까지 내 데이터베이스가 꽤 커지고 있었고 전체 UUID 구현이 성능 문제를 일으킬 것이라는 두려웠습니다. 따라서 완전한 UUID를 사용하는 대신 ID로 무작위로 생성 된 8 자 영숫자 키를 사용하기 시작했으며 충돌을 처리하기 위해 기존 코드를 제자리에 두었습니다. 내 현재 8 자 키와 UUID의 36 자 사이의 어딘가에 불필요한 부풀지 않고 갈등을 제거 할 수있는 달콤한 지점이 있어야하지만 이미 충돌 해결 코드를 가지고 있기 때문에 그 실험에 우선 순위가 아닙니다. .
다음 문제는 히스토리 테이블이 데이터베이스의 나머지 전체보다 약 10 배 더 크다는 것입니다. 이로 인해 저장 비용이 비싸고 기록 테이블의 모든 유지 보수는 고통 스러울 수 있습니다. 전체 테이블을 유지하면 사용자는 이전 변경 사항을 롤백 할 수 있지만 과잉처럼 느껴지기 시작했습니다. 따라서 동기화 프로세스에 루틴을 추가했습니다.이 히스토리 항목이 마지막으로 다운로드 한 히스토리 항목이 더 이상 기록 테이블에 존재하지 않으면 서버는 최근 이력 항목을 제공하지 않고 대신 모든 데이터를 포함하는 파일을 제공합니다. 그 계정. 그런 다음 90 일 이상의 히스토리 항목을 삭제하기 위해 Cronjob을 추가했습니다. 즉, 사용자는 여전히 90 일 미만의 변경 사항을 롤백 할 수 있으며 90 일마다 한 번 이상 동기화되면 업데이트는 이전과 같이 증가합니다. 그러나 90 일 이상 기다리면 앱은 전체 데이터베이스를 대체합니다.
이러한 변화는 히스토리 테이블의 크기를 거의 90%줄였습니다. 이제 히스토리 테이블을 유지하면 데이터베이스가 10 배나 큰 대신 데이터베이스를 두 배나 커집니다. 이 시스템의 또 다른 이점은 필요한 경우 동기화가 히스토리 테이블없이 여전히 작동 할 수 있다는 것입니다. 일시적으로 오프라인으로 가져간 유지 보수를 해야하는 경우와 같이. 또는 다른 가격대에서 계정에 대해 다른 롤백 기간을 제공 할 수 있습니다. 다운로드 할 90 일 이상의 변경 사항이있는 경우 전체 파일은 일반적으로 증분 형식보다 더 효율적입니다.
내가 오늘 다시 시작했다면, ID 충돌 확인을 건너 뛰고 충돌을 제거하기에 충분한 키 길이를 목표로하고, 만일을 대비하여 어떤 종류의 오류를 확인합니다. 그러나 최근 업데이트에 대한 증분 다운로드 또는 필요한 경우 전체 다운로드의 역사 테이블과 조합이 잘 작동했습니다.