Schema Design for Social Inboxes in MongoDB
Designing a schema is a critical part of any application. Like most databases, there are many options for modeling data in MongoDB, and it is important to incorporate the functional requirements and performance goals for your application w
Designing a schema is a critical part of any application. Like most databases, there are many options for modeling data in MongoDB, and it is important to incorporate the functional requirements and performance goals for your application when determining the best design. In this post, we’ll explore three approaches for using MongoDB when creating social inboxes or message timelines.
If you’re building a social network, like Twitter for example, you need to design a schema that is efficient for users viewing their inbox, as well as users sending messages to all their followers. The whole point of social media, after all, is that you can connect in real time.
There are several design considerations for this kind of application:
- The application needs to support a potentially large volume of reads and writes.
- Reads and writes are not uniformly distributed across users. Some users post much more frequently than others, and some users have many, many more followers than others.
- The application must provide a user experience that is instantaneous.
- Edit 11/6: The application will have little to no user deletions of data (a follow up blog post will include information about user deletions and historical data)
Because we are designing an application that needs to support a large volume of reads and writes we will be using a sharded collection for the messages. All three designs include the concept of “fan out,” which refers to distributing the work across the shards in parallel:
- Fan out on Read
- Fan out on Write
- Fan out on Write with Buckets
Each approach presents trade-offs, and you should use the design that is best for your application’s requirements.
The first design you might consider is called Fan Out on Read. When a user sends a message, it is simply saved to the inbox collection. When any user views their own inbox, the application queries for all messages that include the user as a recipient. The messages are returned in descending date order so that users can see the most recent messages.
To implement this design, create a sharded collection called inbox
, specifying the from
field as the shard key, which represents the address sending the message. You can then add a compound index on the to field and the sent field. Once the document is saved into the inbox, the message is effectively sent to all the recipients. With this approach sending messages is very efficient.
Viewing an inbox, on the other hand, is less efficient. When a user views their inbox the application issues a find command based on the to
field, sorted by sent. Because the inbox collection uses from
as its shard key, messages are grouped by sender across the shards. In MongoDB queries that are not based on the shard key will be routed to all shards. Therefore, each inbox view will be routed to all shards in the system. As the system scales and many users go to view their inbox, all queries will be routed to all shards. This design does not scale as well as each query being routed to a single shard.
With the “Fan Out on Read” method, sending a message is very efficient, but viewing the inbox is less efficient.
Fan out on Read is very efficient for sending messages, but less efficient for reading messages. If the majority of your application consists of users sending messages, but very few go to read what anyone sends them — let’s call it an anti-social app — then this design might work well. However, for most social apps there are more requests by users to view their inbox than there are to send messages.
The Fan out on Write takes a different approach that is more optimized for viewing inboxes. This time, instead of sharding our inbox collection on the sender, we shard on the message recipient. In this way, when we go to view an inbox the queries can be routed to a single shard, which will scale very well. Our message document is the same, but now save a copy of the message for every recipient.
With the “Fan Out on Write” method, viewing the inbox is efficient, but sending messages consumes more resources.
In practice we might implement the saving of messages asynchronously. Imagine two celebrities quickly exchange messages at a high-profile event - the system could quickly be saturated with millions of writes. By saving a first copy of their message, then using a pool of background workers to write copies to all followers, we can ensure the two celebrities can exchange messages quickly, and that followers will soon have their own copies. Furthermore, we could maintain a last-viewed date on the user document to ensure they have accessed the system recently - zombie accounts probably shouldn’t get a copy of the message, and for users that haven’t accessed their account recently we could always resort to our first design - Fan out on Read - to repopulate their inbox. Subsequent requests would then be fast again.
At this point we have improved the design for viewing inboxes by routing each inbox view to a single shard. However, each message in the user’s inbox will produce a random read operation. If each inbox view produces 50 random reads, then it only takes a relatively modest number of concurrent users to potentially saturate the disks. Fortunately we can take advantage of the document data model to further optimize this design to be even more efficient.
Fan out on Write with Buckets refines the Fan Out on Write design by “bucketing” messages together into documents of 50 messages ordered by time. When a user views their inbox the request can be fulfilled by reading just a few documents of 50 messages each instead of performing many random reads. Because read time is dominated by seek time, reducing the number of seeks can provide a major performance improvement to the application. Another advantage to this approach is that there are fewer index entries.
To implement this design we create two collections, an inbox collection and a user collection. The inbox collection uses two fields for the shard key, owner
and sequence
, which holds the owner’s user id and sequence number (i.e. the id of 50-message “bucket” documents in their inbox). The user collection contains simple user documents for tracking the total number of messages in their inbox. Since we will probably need to show the total number of messages for a user in a variety of places in our application, this is a nice place to maintain the count instead of calculating for each request. Our message document is the same as in the prior examples.
To send a message we iterate through the list of recipients as we did in the Fan out on Write example, but we also take another step to increment the count of total messages in the inbox of the recipient, which is maintained on the user document. Once we know the count of messages, we know the “bucket” in which to add the latest message. As these messages reach the 50 item threshold, the sequence number increments and we begin to add messages to the next “bucket” document. The most recent messages will always be in the “bucket” document with the highest sequence number. Viewing the most recent 50 messages for a user’s inbox is at most two reads; viewing the most recent 100 messages is at most three reads.
Normally a user’s entire inbox will exist on a single shard. However, it is possible that a few user inboxes could be spread across two shards. Because our application will probably page through a user’s inbox, it is still likely that every query for these few users will be routed to a single shard.
Fan out on Write with Buckets is generally the most scalable approach of the these three designs for social inbox applications. Every design presents different trade-offs. In this case viewing a user’s inbox is very efficient, but writes are somewhat more complex, and more disk space is consumed. For many applications these are the right trade-offs to make.
Schema design is one of the most important optimizations you can make for your application. We have a number of additional resources available on schema design if you are interested in learning more:
Shard per recipient Multiple writes |
Shard per recipient Appends (grows) |
||
Broadcast all shards Random reads |
Single shard Random reads |
Single shard Single read |
|
Message stored once |
Copy per recipient |
Copy per recipient |
Schema design is one of the most important optimizations you can make for your application. We have a number of additional resources available on schema design if you are interested in learning more:
- Check out the recording of our recent Schema Design webinar on this topic.
- Schema Design in general in the MongoDB Manual
- You can also view our schema design resources on the MongoDB docs page
- If you have any schema design questions, please view the archived questions on our user forum or ask a question yourselfon the MongoDB User Forum.
原文地址:Schema Design for Social Inboxes in MongoDB, 感谢原作者分享。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Kernelsecuritycheckfailure(커널 검사 실패)는 비교적 일반적인 유형의 중지 코드입니다. 그러나 이유가 무엇이든 블루 스크린 오류로 인해 많은 사용자가 매우 괴로워합니다. 이 사이트에서는 사용자에게 17가지 유형을 주의 깊게 소개합니다. kernel_security_check_failure 블루 스크린에 대한 17가지 솔루션 방법 1: 모든 외부 장치 제거 사용 중인 외부 장치가 Windows 버전과 호환되지 않으면 Kernelsecuritycheckfailure 블루 스크린 오류가 발생할 수 있습니다. 이렇게 하려면 컴퓨터를 다시 시작하기 전에 모든 외부 장치를 분리해야 합니다.

CMF Watch Pro 2, CMF Phone 1, CMF Buds Pro 2 등 세 가지 신제품이 2024년 7월 8일에 공개될 것이라는 사실은 지난 주에 이미 발표된 바가 없습니다. 이제 제조업체는 이 제품의 새로운 디자인 세부 정보를 공개하는 티저 이미지를 공개했습니다.

Win10 스카이프를 제거할 수 있습니까? 이것은 많은 사용자가 알고 싶어하는 질문입니다. 많은 사용자가 이 응용 프로그램이 컴퓨터의 기본 프로그램에 포함되어 있고 이를 삭제하면 시스템 작동에 영향을 미칠 것이라고 걱정하기 때문입니다. 이 웹사이트 도움말 사용자 Win10에서 비즈니스용 Skype를 제거하는 방법을 자세히 살펴보겠습니다. Win10에서 비즈니스용 Skype를 제거하는 방법 1. 컴퓨터 바탕 화면에서 Windows 아이콘을 클릭한 다음 설정 아이콘을 클릭하여 들어갑니다. 2. "적용"을 클릭하세요. 3. 검색창에 "Skype"를 입력하고 검색된 결과를 클릭하여 선택하세요. 4. "제거"를 클릭하세요. 5

멋지지만 얼룩이지기 쉬운 흰색 Cybertruck 인테리어 외에도 Tesla는 이제 더 많은 색상의 전기 픽업도 제공합니다. 새로운 Tactical Grey Cybertruck 인테리어 색상은 행운의 새로운 덕분에 첫 번째 미리보기를 얻었습니다.

for를 사용하여 n 계승을 찾는 방법: 1. "for (var i=1;i<=n;i++){}" 문을 사용하여 루프 순회 범위를 "1~n"으로 제어합니다. 2. 루프에서; body에서는 "cj *=i"를 사용합니다. 1부터 n까지의 숫자를 곱하고 그 결과를 변수 cj에 할당합니다. 3. 루프가 끝나면 변수 cj의 값이 n의 계승이 되어 출력됩니다.

HMD 글로벌은 스카이라인을 통해 7월 10일 노키아 루미아 920 스타일의 중급형 스마트폰을 공개할 예정이다. 유출자 @smashx_60의 최신 정보에 따르면 루미아 디자인은 곧 태블릿에도 사용될 예정이다. 그것은 c가 될 것이다

차이점: 1. for는 인덱스를 통해 각 데이터 요소를 반복하는 반면 forEach는 JS 기본 프로그램을 통해 배열의 데이터 요소를 반복합니다. 2. for는 break 키워드를 통해 루프 실행을 종료할 수 있지만 forEach는 그렇지 않습니다. for는 루프 변수의 값을 제어하여 루프 실행을 제어할 수 있지만 forEach는 루프 외부에서 루프 변수를 호출할 수 없지만 forEach는 루프 외부에서 루프 변수를 호출할 수 없습니다. forEach보다 높습니다.

Python의 일반적인 흐름 제어 구조는 무엇입니까? Python에서 흐름 제어 구조는 프로그램의 실행 순서를 결정하는 데 사용되는 중요한 도구입니다. 이를 통해 다양한 조건에 따라 다양한 코드 블록을 실행하거나 코드 블록을 반복적으로 실행할 수 있습니다. 다음은 Python의 일반적인 프로세스 제어 구조를 소개하고 해당 코드 예제를 제공합니다. 조건문(if-else): 조건문을 사용하면 다양한 조건에 따라 다양한 코드 블록을 실행할 수 있습니다. 기본 구문은 다음과 같습니다. if 조건 1: #when 조건
