짧은 대답은 새로운 데이터 만 유선으로 전송된다는 것입니다. 작동 방식은 다음과 같습니다.
Meteor 서버에는 구독을 관리하는 세 가지 중요한 부분이 있습니다. 구독이 제공하는 데이터에 대한 논리를 정의하는 게시 기능 ; 몽고 드라이버 변경에 대한 데이터베이스를 시계; 및 클라이언트의 모든 활성 구독을 결합하여 네트워크를 통해 클라이언트로 보내는 병합 상자 .
게시 기능
Meteor 클라이언트가 컬렉션을 구독 할 때마다 서버는 게시 기능을 실행
합니다 . 게시 기능의 역할은 클라이언트가 가져야하는 문서 세트를 파악하고 각 문서 속성을 병합 상자로 보내는 것입니다. 새 구독 클라이언트마다 한 번씩 실행됩니다. 를 사용하는 임의의 복잡한 액세스 제어와 같이 게시 기능에 원하는 JavaScript를 넣을 수 있습니다 this.userId
. 는 함수가 호출하여 병합 상자에 데이터를 전송 게시 this.added
, this.changed
하고
this.removed
. 자세한 내용은
전체 게시 문서 를 참조하세요.
게시 대부분의 기능은 낮은 수준의 주위에 깨끗이 할 필요가 없습니다
added
, changed
그리고 removed
하지만, API. A는 함수를 리턴한다 몽고 커서를 게시하면, 유성 서버는 자동으로 몽고 드라이버 (의 출력에 연결 insert
, update
및 removed
병합 상자의 입력에 콜백을 () this.added
, this.changed
및 this.removed
). 게시 기능에서 모든 권한 확인을 미리 수행 한 다음 사용자 코드없이 데이터베이스 드라이버를 병합 상자에 직접 연결할 수 있다는 것은 매우 깔끔합니다. 그리고 자동 게시가 설정되면이 작은 부분조차 숨겨집니다. 서버는 각 컬렉션의 모든 문서에 대한 쿼리를 자동으로 설정하고 병합 상자로 푸시합니다.
반면에 데이터베이스 쿼리 게시에만 국한되지 않습니다. 예를 들어 내부의 기기에서 GPS 위치를 읽 Meteor.setInterval
거나 다른 웹 서비스에서 레거시 REST API를 폴링하는 게시 함수를 작성할 수 있습니다 . 이러한 경우에, 당신은 낮은 수준을 호출하여 병합 상자의 변경을 방출 것 added
, changed
및 removed
DDP API.
몽고 드라이버
몽고 드라이버의 작업은 라이브 쿼리에 대한 변경 사항 몽고 데이터베이스를 시청하는 것입니다. 이러한 쿼리는 계속 실행 added
되며 removed
, 및 changed
콜백 을 호출하여 결과가 변경되면 업데이트를 반환합니다 .
Mongo는 실시간 데이터베이스가 아닙니다. 그래서 운전자가 투표합니다. 각 활성 라이브 쿼리에 대한 마지막 쿼리 결과의 메모리 내 복사본을 유지합니다. 각 폴링주기에, 그것은의 최소 세트 컴퓨팅, 이전 저장 결과 새로운 결과를 비교 added
, removed
그리고 changed
그 차이를 설명하는 이벤트. 여러 호출자가 동일한 라이브 쿼리에 대한 콜백을 등록하는 경우 드라이버는 쿼리의 복사본 하나만 감시하여 동일한 결과로 등록 된 각 콜백을 호출합니다.
서버가 컬렉션을 업데이트 할 때마다 드라이버는 해당 컬렉션에 대한 각 라이브 쿼리를 다시 계산합니다 (향후 Meteor 버전에서는 업데이트시 다시 계산되는 라이브 쿼리를 제한하기 위해 스케일링 API를 제공합니다.) 또한 드라이버는 10 초 타이머에서 각 라이브 쿼리를 폴링하여 Meteor 서버를 우회하는 대역 외 데이터베이스 업데이트를 포착합니다.
병합 상자
의 작업 병합 상자 결과 (결합하는 것입니다 added
, changed
그리고 removed
단일 데이터 스트림으로 클라이언트의 활성 게시의 모든 기능 통화). 연결된 각 클라이언트에 대해 하나의 병합 상자가 있습니다. 클라이언트의 minimongo 캐시의 전체 사본을 보유합니다.
단일 구독이있는 예에서 병합 상자는 기본적으로 통과입니다. 그러나 더 복잡한 앱에는 중복 될 수있는 여러 구독이있을 수 있습니다. 두 구독이 모두 동일한 문서에 동일한 속성을 설정하면 병합 상자는 우선 순위를 갖는 값을 결정하고 클라이언트에게만 보냅니다. 아직 구독 우선 순위 설정을위한 API를 공개하지 않았습니다. 현재 우선 순위는 클라이언트가 데이터 세트를 구독하는 순서에 따라 결정됩니다. 클라이언트가 만드는 첫 번째 구독이 가장 높은 우선 순위를 가지며 두 번째 구독이 그 다음으로 높은 방식입니다.
병합 상자는 클라이언트의 상태를 유지하기 때문에 게시 기능이 제공하는 내용에 관계없이 각 클라이언트를 최신 상태로 유지하기 위해 최소한의 데이터를 보낼 수 있습니다.
업데이트시 발생하는 사항
이제 시나리오에 대한 단계를 설정했습니다.
1,000 개의 연결된 클라이언트가 있습니다. 각각은 동일한 라이브 Mongo 쿼리 ( Somestuff.find({})
)를 구독합니다 . 쿼리는 각 클라이언트에 대해 동일하므로 드라이버는 하나의 라이브 쿼리 만 실행합니다. 1,000 개의 활성 병합 상자가 있습니다. 그리고 각 클라이언트의 기능이 등록 게시 added
, changed
그리고
removed
그 라이브 쿼리 병합 상자 중 하나에 피드가. 병합 상자에 다른 것은 연결되어 있지 않습니다.
먼저 몽고 드라이버. 클라이언트 중 하나가에 새 문서를 삽입 Somestuff
하면 재 계산이 트리거됩니다. Mongo 드라이버는의 모든 문서에 대한 쿼리를 다시 실행하고 Somestuff
, 결과를 메모리의 이전 결과와 비교하고, 새 문서가 하나 있음을 확인하고, 1,000 개의 등록 된 insert
콜백을 각각 호출합니다.
다음으로 게시 기능입니다. 여기서는 거의 일어나지 않습니다. 1,000 개의 insert
콜백 각각 은를 호출하여 병합 상자로 데이터를 푸시합니다 added
.
마지막으로 각 병합 상자는 클라이언트 캐시의 메모리 내 사본에 대해 이러한 새 속성을 확인합니다. 각각의 경우 값이 아직 클라이언트에 없으며 기존 값을 숨기지 않음을 발견합니다. 따라서 병합 상자 DATA
는 클라이언트에 대한 SockJS 연결에서 DDP 메시지를 내보내고 서버 측 메모리 내 복사본을 업데이트합니다.
총 CPU 비용은 하나의 Mongo 쿼리를 비교하는 비용과 클라이언트의 상태를 확인하고 새로운 DDP 메시지 페이로드를 구성하는 1,000 개의 병합 상자 비용을 더한 비용입니다. 유선을 통해 흐르는 유일한 데이터는 데이터베이스의 새 문서에 해당하는 1,000 개의 클라이언트 각각에 전송 된 단일 JSON 개체와 원본 삽입을 만든 클라이언트 에서 서버 로 보내는 하나의 RPC 메시지 입니다.
최적화
우리가 확실히 계획 한 것은 다음과 같습니다.
보다 효율적인 Mongo 드라이버. 우리는
드라이버를 최적화 된
별개의 쿼리 당 하나의 관찰자를 실행하는 0.5.1에서.
모든 DB 변경이 쿼리 재 계산을 트리거하는 것은 아닙니다. 일부 자동 개선을 수행 할 수 있지만 가장 좋은 방법은 개발자가 재실행이 필요한 쿼리를 지정할 수있는 API입니다. 예를 들어, 하나의 채팅방에 메시지를 삽입하는 것이 두 번째 방의 메시지에 대한 실시간 쿼리를 무효화해서는 안된다는 것은 개발자에게 분명합니다.
Mongo 드라이버, 게시 기능 및 병합 상자는 동일한 프로세스 또는 동일한 시스템에서 실행할 필요가 없습니다. 일부 애플리케이션은 복잡한 라이브 쿼리를 실행하고 데이터베이스를보기 위해 더 많은 CPU가 필요합니다. 다른 쿼리에는 몇 가지 고유 한 쿼리 만 있지만 (블로그 엔진을 상상해보세요) 연결된 클라이언트가 많을 수 있습니다. 이러한 클라이언트에는 병합 상자에 더 많은 CPU가 필요합니다. 이러한 구성 요소를 분리하면 각 조각을 독립적으로 확장 할 수 있습니다.
많은 데이터베이스는 행이 업데이트 될 때 실행되는 트리거를 지원하고 이전 및 새 행을 제공합니다. 이 기능을 사용하면 데이터베이스 드라이버가 변경 사항을 폴링하는 대신 트리거를 등록 할 수 있습니다.