You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3157 lines
86 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!doctype html>
<html lang="zh" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="开发知识wiki">
<meta name="author" content="tink">
<link rel="canonical" href="https://docs.cyub.vip/dev-wiki/system-design/system-design-primer/solutions/system_design/twitter/">
<link rel="icon" href="../../../../../images/favicon.ico">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.4.4">
<title>Design the Twitter timeline and search - 开发知识wiki</title>
<link rel="stylesheet" href="../../../../../assets/stylesheets/main.bd3936ea.min.css">
<link rel="stylesheet" href="../../../../../assets/stylesheets/palette.356b1318.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Fira+Code:300,300i,400,400i,700,700i%7CFira+Code:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Fira Code";--md-code-font:"Fira Code"}</style>
<link rel="stylesheet" href="../../../../../css/print-site-enum-headings1.css">
<link rel="stylesheet" href="../../../../../css/print-site-enum-headings2.css">
<link rel="stylesheet" href="../../../../../css/print-site-enum-headings3.css">
<link rel="stylesheet" href="../../../../../css/print-site-enum-headings4.css">
<link rel="stylesheet" href="../../../../../css/print-site-enum-headings5.css">
<link rel="stylesheet" href="../../../../../css/print-site-enum-headings6.css">
<link rel="stylesheet" href="../../../../../css/print-site.css">
<link rel="stylesheet" href="../../../../../css/print-site-material.css">
<script>__md_scope=new URL("../../../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<script id="__analytics">function __md_analytics(){function n(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],n("js",new Date),n("config",""),document.addEventListener("DOMContentLoaded",function(){document.forms.search&&document.forms.search.query.addEventListener("blur",function(){this.value&&n("event","search",{search_term:this.value})}),document$.subscribe(function(){var a=document.forms.feedback;if(void 0!==a)for(var e of a.querySelectorAll("[type=submit]"))e.addEventListener("click",function(e){e.preventDefault();var t=document.location.pathname,e=this.getAttribute("data-md-value");n("event","feedback",{page:t,data:e}),a.firstElementChild.disabled=!0;e=a.querySelector(".md-feedback__note [data-md-value='"+e+"']");e&&(e.hidden=!1)}),a.hidden=!1}),location$.subscribe(function(e){n("config","",{page_path:e.pathname})})});var e=document.createElement("script");e.async=!0,e.src="https://www.googletagmanager.com/gtag/js?id=",document.getElementById("__analytics").insertAdjacentElement("afterEnd",e)}</script>
<script>"undefined"!=typeof __md_analytics&&__md_analytics()</script>
<link href="../../../../../assets/stylesheets/glightbox.min.css" rel="stylesheet"/><style>
html.glightbox-open { overflow: initial; height: 100%; }
.gslide-title { margin-top: 0px; user-select: text; }
.gslide-desc { color: #666; user-select: text; }
.gslide-image img { background: white; }
.gscrollbar-fixer { padding-right: 15px; }
.gdesc-inner { font-size: 0.75rem; }
body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}</style> <script src="../../../../../assets/javascripts/glightbox.min.js"></script></head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo">
<script>var palette=__md_get("__palette");if(palette&&"object"==typeof palette.color)for(var key of Object.keys(palette.color))document.body.setAttribute("data-md-color-"+key,palette.color[key])</script>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#design-the-twitter-timeline-and-search" class="md-skip">
跳转至
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="页眉">
<a href="../../../../.." title="开发知识wiki" class="md-header__button md-logo" aria-label="开发知识wiki" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 89 89">
<path d="M3.136,17.387l0,42.932l42.932,21.467l-42.932,-64.399Z" />
<path d="M21.91,8l42.933,64.398l-18.775,9.388l-42.932,-64.399l18.774,-9.387Z" style="fill-opacity: 0.5" />
<path d="M67.535,17.387l-27.262,18.156l21.878,32.818l5.384,2.691l0,-53.665Z" />
<path d="M67.535,17.387l0,53.666l18.774,-9.388l0,-53.665l-18.774,9.387Z" style="fill-opacity: 0.25" />
</svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
开发知识wiki
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Design the Twitter timeline and search
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme)" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_3" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1M8 13h8v-2H8v2m9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1 0 1.71-1.39 3.1-3.1 3.1h-4V17h4a5 5 0 0 0 5-5 5 5 0 0 0-5-5Z"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_2">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5m0 8a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3Z"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to system preference" type="radio" name="__palette" id="__palette_3">
<label class="md-header__button md-icon" title="Switch to system preference" for="__palette_2" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5M7 15a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3Z"/></svg>
</label>
</form>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="搜索" placeholder="搜索" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="查找">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="分享" aria-label="分享" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7 0-.24-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91 1.61 0 2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08Z"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="清空当前内容" aria-label="清空当前内容" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
正在初始化搜索引擎
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="标签" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../../../.." class="md-tabs__link">
简介
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../computer-system/io/" class="md-tabs__link">
操作系统
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../computer-network/tcp/" class="md-tabs__link">
计算机网络
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../database/mysql/%E7%AE%80%E4%BB%8B/" class="md-tabs__link">
数据库
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../language/Go/" class="md-tabs__link">
开发语言
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../" class="md-tabs__link">
系统设计
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../jupyter/Go-Frameworks-Github-Fork-Stats/" class="md-tabs__link">
Jupyter
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../video/os/" class="md-tabs__link">
视频
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../../qa/redis/" class="md-tabs__link">
QA
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="导航栏" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../../../.." title="开发知识wiki" class="md-nav__button md-logo" aria-label="开发知识wiki" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 89 89">
<path d="M3.136,17.387l0,42.932l42.932,21.467l-42.932,-64.399Z" />
<path d="M21.91,8l42.933,64.398l-18.775,9.388l-42.932,-64.399l18.774,-9.387Z" style="fill-opacity: 0.5" />
<path d="M67.535,17.387l-27.262,18.156l21.878,32.818l5.384,2.691l0,-53.665Z" />
<path d="M67.535,17.387l0,53.666l18.774,-9.388l0,-53.665l-18.774,9.387Z" style="fill-opacity: 0.25" />
</svg>
</a>
开发知识wiki
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../.." class="md-nav__link">
<span class="md-ellipsis">
简介
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-ellipsis">
操作系统
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
操作系统
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../computer-system/io/" class="md-nav__link">
<span class="md-ellipsis">
IO
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../computer-system/proc/" class="md-nav__link">
<span class="md-ellipsis">
proc文件系统
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../computer-system/nptl/" class="md-nav__link">
<span class="md-ellipsis">
NPTL
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_4" >
<label class="md-nav__link" for="__nav_2_4" id="__nav_2_4_label" tabindex="">
<span class="md-ellipsis">
容器
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_4">
<span class="md-nav__icon md-icon"></span>
容器
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../container/install/" class="md-nav__link">
<span class="md-ellipsis">
简介
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../container/image/" class="md-nav__link">
<span class="md-ellipsis">
镜像
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../container/cgroup/" class="md-nav__link">
<span class="md-ellipsis">
cgroup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../container/namespace/" class="md-nav__link">
<span class="md-ellipsis">
namespace
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../../../../computer-system/command/" class="md-nav__link">
<span class="md-ellipsis">
常用命令
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../computer-system/systemtap/" class="md-nav__link">
<span class="md-ellipsis">
Systemtap
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../computer-system/cpu-arch/" class="md-nav__link">
<span class="md-ellipsis">
CPU架构
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../computer-system/compiling-linux-kernel/" class="md-nav__link">
<span class="md-ellipsis">
编译Linux内核
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
<div class="md-nav__link md-nav__container">
<a href="../../../../../computer-network/tcp/" class="md-nav__link ">
<span class="md-ellipsis">
计算机网络
</span>
</a>
<label class="md-nav__link " for="__nav_3" id="__nav_3_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
计算机网络
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../computer-network/http/" class="md-nav__link">
<span class="md-ellipsis">
HTTP
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="">
<span class="md-ellipsis">
数据库
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
数据库
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_1" >
<label class="md-nav__link" for="__nav_4_1" id="__nav_4_1_label" tabindex="">
<span class="md-ellipsis">
mysql
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_1">
<span class="md-nav__icon md-icon"></span>
mysql
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../database/mysql/%E7%AE%80%E4%BB%8B/" class="md-nav__link">
<span class="md-ellipsis">
概览
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../database/mysql/%E4%BA%8B%E5%8A%A1/" class="md-nav__link">
<span class="md-ellipsis">
事务
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../database/mysql/%E7%B4%A2%E5%BC%95/" class="md-nav__link">
<span class="md-ellipsis">
索引
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../database/mysql/FAQ/" class="md-nav__link">
<span class="md-ellipsis">
FAQ
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_2" >
<div class="md-nav__link md-nav__container">
<a href="../../../../../database/elasticsearch/" class="md-nav__link ">
<span class="md-ellipsis">
Elasticsearch
</span>
</a>
<label class="md-nav__link " for="__nav_4_2" id="__nav_4_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_2">
<span class="md-nav__icon md-icon"></span>
Elasticsearch
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../database/elasticsearch/memory/" class="md-nav__link">
<span class="md-ellipsis">
内存占用
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../database/elasticsearch/performance_tuning/" class="md-nav__link">
<span class="md-ellipsis">
性能调优
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../database/elasticsearch/production_configuring/" class="md-nav__link">
<span class="md-ellipsis">
生产配置参考
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../database/elasticsearch/doc_values_and_fielddata/" class="md-nav__link">
<span class="md-ellipsis">
docs value与 field data
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../../../../database/redis/redis/" class="md-nav__link">
<span class="md-ellipsis">
Redis
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<span class="md-ellipsis">
开发语言
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
开发语言
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../language/Go/" class="md-nav__link">
<span class="md-ellipsis">
Go
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
<div class="md-nav__link md-nav__container">
<a href="../../../../" class="md-nav__link ">
<span class="md-ellipsis">
系统设计
</span>
</a>
<label class="md-nav__link " for="__nav_6" id="__nav_6_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
系统设计
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../cache/" class="md-nav__link">
<span class="md-ellipsis">
缓存系统
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../" class="md-nav__link">
<span class="md-ellipsis">
系统设计入门
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_4" >
<div class="md-nav__link md-nav__container">
<a href="../../../../../what-should-you-know/" class="md-nav__link ">
<span class="md-ellipsis">
what you should know
</span>
</a>
<label class="md-nav__link " for="__nav_6_4" id="__nav_6_4_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_6_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6_4">
<span class="md-nav__icon md-icon"></span>
what you should know
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../what-should-you-know/GPU/" class="md-nav__link">
<span class="md-ellipsis">
每个开发人员都应该了解 GPU 计算的知识
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../what-should-you-know/hardware/" class="md-nav__link">
<span class="md-ellipsis">
每个程序员都应该了解的硬件知识
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_4_4" >
<label class="md-nav__link" for="__nav_6_4_4" id="__nav_6_4_4_label" tabindex="0">
<span class="md-ellipsis">
每个程序员都应该了解的内存知识
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_6_4_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6_4_4">
<span class="md-nav__icon md-icon"></span>
每个程序员都应该了解的内存知识
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../what-should-you-know/%E6%AF%8F%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%91%98%E9%83%BD%E5%BA%94%E8%AF%A5%E4%BA%86%E8%A7%A3%E7%9A%84%E5%86%85%E5%AD%98%E7%9F%A5%E8%AF%86/" class="md-nav__link">
<span class="md-ellipsis">
【总结版】每个程序员都应该了解的内存知识
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../what-should-you-know/What%20Every%20Programmer%20Should%20Know%20About%20Memory.pdf" class="md-nav__link">
<span class="md-ellipsis">
【英文】What Every Programmer Should Know About Memory
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../what-should-you-know/%E6%AF%8F%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%91%98%E9%83%BD%E5%BA%94%E8%AF%A5%E4%BA%86%E8%A7%A3%E7%9A%84%E5%86%85%E5%AD%98%E7%9F%A5%E8%AF%86.pdf" class="md-nav__link">
<span class="md-ellipsis">
【中文】每个程序员都应该了解的内存知识
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_4_5" >
<label class="md-nav__link" for="__nav_6_4_5" id="__nav_6_4_5_label" tabindex="0">
<span class="md-ellipsis">
每个系统程序员都应该了解的并发知识
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_6_4_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6_4_5">
<span class="md-nav__icon md-icon"></span>
每个系统程序员都应该了解的并发知识
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../what-should-you-know/concurrency-primer.pdf" class="md-nav__link">
<span class="md-ellipsis">
【英文】What every systems programmer should know about concurrency
</span>
</a>
</li>
<li class="md-nav__item">
<a href="https://www.bilibili.com/read/cv26734224" class="md-nav__link">
<span class="md-ellipsis">
【中文】每个系统程序员都应该了解的并发知识
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_7" >
<label class="md-nav__link" for="__nav_7" id="__nav_7_label" tabindex="">
<span class="md-ellipsis">
Jupyter
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Jupyter
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../jupyter/Go-Frameworks-Github-Fork-Stats/" class="md-nav__link">
<span class="md-ellipsis">
Go-Frameworks-Github-Fork-Stats
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../jupyter/Pandas%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/" class="md-nav__link">
<span class="md-ellipsis">
Pandas完全指南
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_7_3" >
<label class="md-nav__link" for="__nav_7_3" id="__nav_7_3_label" tabindex="">
<span class="md-ellipsis">
Spark上手示例
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_7_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_7_3">
<span class="md-nav__icon md-icon"></span>
Spark上手示例
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../jupyter/Spark%E4%B8%8A%E6%89%8B%E7%A4%BA%E4%BE%8B1%EF%BC%9ARDD%E6%93%8D%E4%BD%9C/" class="md-nav__link">
<span class="md-ellipsis">
Spark上手示例1RDD操作
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../jupyter/Spark%E4%B8%8A%E6%89%8B%E7%A4%BA%E4%BE%8B2%EF%BC%9ADataFrame%E6%93%8D%E4%BD%9C/" class="md-nav__link">
<span class="md-ellipsis">
Spark上手示例2DataFrame操作
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_8" >
<label class="md-nav__link" for="__nav_8" id="__nav_8_label" tabindex="">
<span class="md-ellipsis">
视频
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_8">
<span class="md-nav__icon md-icon"></span>
视频
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../video/os/" class="md-nav__link">
<span class="md-ellipsis">
操作系统
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../video/Data%20structures/" class="md-nav__link">
<span class="md-ellipsis">
数据结构与算法
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../video/c_c%2B%2B/" class="md-nav__link">
<span class="md-ellipsis">
C/C++
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../video/Go/" class="md-nav__link">
<span class="md-ellipsis">
Go
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_9" >
<label class="md-nav__link" for="__nav_9" id="__nav_9_label" tabindex="">
<span class="md-ellipsis">
QA
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_9">
<span class="md-nav__icon md-icon"></span>
QA
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../../../qa/redis/" class="md-nav__link">
<span class="md-ellipsis">
redis
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/mysql/" class="md-nav__link">
<span class="md-ellipsis">
mysql
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/tcp/" class="md-nav__link">
<span class="md-ellipsis">
tcp
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/http/" class="md-nav__link">
<span class="md-ellipsis">
http
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/cache/" class="md-nav__link">
<span class="md-ellipsis">
缓存
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/nginx/" class="md-nav__link">
<span class="md-ellipsis">
nginx
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/queue/" class="md-nav__link">
<span class="md-ellipsis">
消息队列
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/io/" class="md-nav__link">
<span class="md-ellipsis">
IO
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/protobuf/" class="md-nav__link">
<span class="md-ellipsis">
protobuf
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/go/" class="md-nav__link">
<span class="md-ellipsis">
go
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/dist/" class="md-nav__link">
<span class="md-ellipsis">
分布式
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/es/" class="md-nav__link">
<span class="md-ellipsis">
Elasticsearch
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/docker/" class="md-nav__link">
<span class="md-ellipsis">
docker
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../../../qa/ref/" class="md-nav__link">
<span class="md-ellipsis">
参考资料
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="目录">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
目录
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#step-1-outline-use-cases-and-constraints" class="md-nav__link">
Step 1: Outline use cases and constraints
</a>
<nav class="md-nav" aria-label="Step 1: Outline use cases and constraints">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#use-cases" class="md-nav__link">
Use cases
</a>
<nav class="md-nav" aria-label="Use cases">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#well-scope-the-problem-to-handle-only-the-following-use-cases" class="md-nav__link">
We'll scope the problem to handle only the following use cases
</a>
</li>
<li class="md-nav__item">
<a href="#out-of-scope" class="md-nav__link">
Out of scope
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#constraints-and-assumptions" class="md-nav__link">
Constraints and assumptions
</a>
<nav class="md-nav" aria-label="Constraints and assumptions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#state-assumptions" class="md-nav__link">
State assumptions
</a>
</li>
<li class="md-nav__item">
<a href="#calculate-usage" class="md-nav__link">
Calculate usage
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#step-2-create-a-high-level-design" class="md-nav__link">
Step 2: Create a high level design
</a>
</li>
<li class="md-nav__item">
<a href="#step-3-design-core-components" class="md-nav__link">
Step 3: Design core components
</a>
<nav class="md-nav" aria-label="Step 3: Design core components">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#use-case-user-posts-a-tweet" class="md-nav__link">
Use case: User posts a tweet
</a>
</li>
<li class="md-nav__item">
<a href="#use-case-user-views-the-home-timeline" class="md-nav__link">
Use case: User views the home timeline
</a>
</li>
<li class="md-nav__item">
<a href="#use-case-user-views-the-user-timeline" class="md-nav__link">
Use case: User views the user timeline
</a>
</li>
<li class="md-nav__item">
<a href="#use-case-user-searches-keywords" class="md-nav__link">
Use case: User searches keywords
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#step-4-scale-the-design" class="md-nav__link">
Step 4: Scale the design
</a>
</li>
<li class="md-nav__item">
<a href="#additional-talking-points" class="md-nav__link">
Additional talking points
</a>
<nav class="md-nav" aria-label="Additional talking points">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#nosql" class="md-nav__link">
NoSQL
</a>
</li>
<li class="md-nav__item">
<a href="#caching" class="md-nav__link">
Caching
</a>
</li>
<li class="md-nav__item">
<a href="#asynchronism-and-microservices" class="md-nav__link">
Asynchronism and microservices
</a>
</li>
<li class="md-nav__item">
<a href="#communications" class="md-nav__link">
Communications
</a>
</li>
<li class="md-nav__item">
<a href="#security" class="md-nav__link">
Security
</a>
</li>
<li class="md-nav__item">
<a href="#latency-numbers" class="md-nav__link">
Latency numbers
</a>
</li>
<li class="md-nav__item">
<a href="#ongoing" class="md-nav__link">
Ongoing
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="design-the-twitter-timeline-and-search">Design the Twitter timeline and search<a class="headerlink" href="#design-the-twitter-timeline-and-search" title="Permanent link">&para;</a></h1>
<p><em>Note: This document links directly to relevant areas found in the <a href="https://github.com/donnemartin/system-design-primer#index-of-system-design-topics">system design topics</a> to avoid duplication. Refer to the linked content for general talking points, tradeoffs, and alternatives.</em></p>
<p><strong>Design the Facebook feed</strong> and <strong>Design Facebook search</strong> are similar questions.</p>
<h2 id="step-1-outline-use-cases-and-constraints">Step 1: Outline use cases and constraints<a class="headerlink" href="#step-1-outline-use-cases-and-constraints" title="Permanent link">&para;</a></h2>
<blockquote>
<p>Gather requirements and scope the problem.
Ask questions to clarify use cases and constraints.
Discuss assumptions.</p>
</blockquote>
<p>Without an interviewer to address clarifying questions, we'll define some use cases and constraints.</p>
<h3 id="use-cases">Use cases<a class="headerlink" href="#use-cases" title="Permanent link">&para;</a></h3>
<h4 id="well-scope-the-problem-to-handle-only-the-following-use-cases">We'll scope the problem to handle only the following use cases<a class="headerlink" href="#well-scope-the-problem-to-handle-only-the-following-use-cases" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>User</strong> posts a tweet<ul>
<li><strong>Service</strong> pushes tweets to followers, sending push notifications and emails</li>
</ul>
</li>
<li><strong>User</strong> views the user timeline (activity from the user)</li>
<li><strong>User</strong> views the home timeline (activity from people the user is following)</li>
<li><strong>User</strong> searches keywords</li>
<li><strong>Service</strong> has high availability</li>
</ul>
<h4 id="out-of-scope">Out of scope<a class="headerlink" href="#out-of-scope" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Service</strong> pushes tweets to the Twitter Firehose and other streams</li>
<li><strong>Service</strong> strips out tweets based on users' visibility settings<ul>
<li>Hide <a class="magiclink magiclink-github magiclink-mention" href="https://github.com/reply" title="GitHub User: reply">@reply</a> if the user is not also following the person being replied to</li>
<li>Respect 'hide retweets' setting</li>
</ul>
</li>
<li>Analytics</li>
</ul>
<h3 id="constraints-and-assumptions">Constraints and assumptions<a class="headerlink" href="#constraints-and-assumptions" title="Permanent link">&para;</a></h3>
<h4 id="state-assumptions">State assumptions<a class="headerlink" href="#state-assumptions" title="Permanent link">&para;</a></h4>
<p>General</p>
<ul>
<li>Traffic is not evenly distributed</li>
<li>Posting a tweet should be fast<ul>
<li>Fanning out a tweet to all of your followers should be fast, unless you have millions of followers</li>
</ul>
</li>
<li>100 million active users</li>
<li>500 million tweets per day or 15 billion tweets per month<ul>
<li>Each tweet averages a fanout of 10 deliveries</li>
<li>5 billion total tweets delivered on fanout per day</li>
<li>150 billion tweets delivered on fanout per month</li>
</ul>
</li>
<li>250 billion read requests per month</li>
<li>10 billion searches per month</li>
</ul>
<p>Timeline</p>
<ul>
<li>Viewing the timeline should be fast</li>
<li>Twitter is more read heavy than write heavy<ul>
<li>Optimize for fast reads of tweets</li>
</ul>
</li>
<li>Ingesting tweets is write heavy</li>
</ul>
<p>Search</p>
<ul>
<li>Searching should be fast</li>
<li>Search is read-heavy</li>
</ul>
<h4 id="calculate-usage">Calculate usage<a class="headerlink" href="#calculate-usage" title="Permanent link">&para;</a></h4>
<p><strong>Clarify with your interviewer if you should run back-of-the-envelope usage calculations.</strong></p>
<ul>
<li>Size per tweet:<ul>
<li><code>tweet_id</code> - 8 bytes</li>
<li><code>user_id</code> - 32 bytes</li>
<li><code>text</code> - 140 bytes</li>
<li><code>media</code> - 10 KB average</li>
<li>Total: ~10 KB</li>
</ul>
</li>
<li>150 TB of new tweet content per month<ul>
<li>10 KB per tweet * 500 million tweets per day * 30 days per month</li>
<li>5.4 PB of new tweet content in 3 years</li>
</ul>
</li>
<li>100 thousand read requests per second<ul>
<li>250 billion read requests per month * (400 requests per second / 1 billion requests per month)</li>
</ul>
</li>
<li>6,000 tweets per second<ul>
<li>15 billion tweets per month * (400 requests per second / 1 billion requests per month)</li>
</ul>
</li>
<li>60 thousand tweets delivered on fanout per second<ul>
<li>150 billion tweets delivered on fanout per month * (400 requests per second / 1 billion requests per month)</li>
</ul>
</li>
<li>4,000 search requests per second<ul>
<li>10 billion searches per month * (400 requests per second / 1 billion requests per month)</li>
</ul>
</li>
</ul>
<p>Handy conversion guide:</p>
<ul>
<li>2.5 million seconds per month</li>
<li>1 request per second = 2.5 million requests per month</li>
<li>40 requests per second = 100 million requests per month</li>
<li>400 requests per second = 1 billion requests per month</li>
</ul>
<h2 id="step-2-create-a-high-level-design">Step 2: Create a high level design<a class="headerlink" href="#step-2-create-a-high-level-design" title="Permanent link">&para;</a></h2>
<blockquote>
<p>Outline a high level design with all important components.</p>
</blockquote>
<p><a class="glightbox" href="http://i.imgur.com/48tEA2j.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="Imgur" src="http://i.imgur.com/48tEA2j.png" /></a></p>
<h2 id="step-3-design-core-components">Step 3: Design core components<a class="headerlink" href="#step-3-design-core-components" title="Permanent link">&para;</a></h2>
<blockquote>
<p>Dive into details for each core component.</p>
</blockquote>
<h3 id="use-case-user-posts-a-tweet">Use case: User posts a tweet<a class="headerlink" href="#use-case-user-posts-a-tweet" title="Permanent link">&para;</a></h3>
<p>We could store the user's own tweets to populate the user timeline (activity from the user) in a <a href="https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms">relational database</a>. We should discuss the <a href="https://github.com/donnemartin/system-design-primer#sql-or-nosql">use cases and tradeoffs between choosing SQL or NoSQL</a>.</p>
<p>Delivering tweets and building the home timeline (activity from people the user is following) is trickier. Fanning out tweets to all followers (60 thousand tweets delivered on fanout per second) will overload a traditional <a href="https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms">relational database</a>. We'll probably want to choose a data store with fast writes such as a <strong>NoSQL database</strong> or <strong>Memory Cache</strong>. Reading 1 MB sequentially from memory takes about 250 microseconds, while reading from SSD takes 4x and from disk takes 80x longer.<sup><a href=https://github.com/donnemartin/system-design-primer#latency-numbers-every-programmer-should-know>1</a></sup></p>
<p>We could store media such as photos or videos on an <strong>Object Store</strong>.</p>
<ul>
<li>The <strong>Client</strong> posts a tweet to the <strong>Web Server</strong>, running as a <a href="https://github.com/donnemartin/system-design-primer#reverse-proxy-web-server">reverse proxy</a></li>
<li>The <strong>Web Server</strong> forwards the request to the <strong>Write API</strong> server</li>
<li>The <strong>Write API</strong> stores the tweet in the user's timeline on a <strong>SQL database</strong></li>
<li>The <strong>Write API</strong> contacts the <strong>Fan Out Service</strong>, which does the following:<ul>
<li>Queries the <strong>User Graph Service</strong> to find the user's followers stored in the <strong>Memory Cache</strong></li>
<li>Stores the tweet in the <em>home timeline of the user's followers</em> in a <strong>Memory Cache</strong><ul>
<li>O(n) operation: 1,000 followers = 1,000 lookups and inserts</li>
</ul>
</li>
<li>Stores the tweet in the <strong>Search Index Service</strong> to enable fast searching</li>
<li>Stores media in the <strong>Object Store</strong></li>
<li>Uses the <strong>Notification Service</strong> to send out push notifications to followers:<ul>
<li>Uses a <strong>Queue</strong> (not pictured) to asynchronously send out notifications</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>Clarify with your interviewer how much code you are expected to write</strong>.</p>
<p>If our <strong>Memory Cache</strong> is Redis, we could use a native Redis list with the following structure:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a> tweet n+2 tweet n+1 tweet n
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>| 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte |
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>| tweet_id user_id meta | tweet_id user_id meta | tweet_id user_id meta |
</span></code></pre></div>
<p>The new tweet would be placed in the <strong>Memory Cache</strong>, which populates the user's home timeline (activity from people the user is following).</p>
<p>We'll use a public <a href="https://github.com/donnemartin/system-design-primer#representational-state-transfer-rest"><strong>REST API</strong></a>:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>$ curl -X POST --data &#39;{ &quot;user_id&quot;: &quot;123&quot;, &quot;auth_token&quot;: &quot;ABC123&quot;, \
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a> &quot;status&quot;: &quot;hello world!&quot;, &quot;media_ids&quot;: &quot;ABC987&quot; }&#39; \
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a> https://twitter.com/api/v1/tweet
</span></code></pre></div>
<p>Response:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>{
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> &quot;created_at&quot;: &quot;Wed Sep 05 00:37:15 +0000 2012&quot;,
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a> &quot;status&quot;: &quot;hello world!&quot;,
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a> &quot;tweet_id&quot;: &quot;987&quot;,
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a> &quot;user_id&quot;: &quot;123&quot;,
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a> ...
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a>}
</span></code></pre></div>
<p>For internal communications, we could use <a href="https://github.com/donnemartin/system-design-primer#remote-procedure-call-rpc">Remote Procedure Calls</a>.</p>
<h3 id="use-case-user-views-the-home-timeline">Use case: User views the home timeline<a class="headerlink" href="#use-case-user-views-the-home-timeline" title="Permanent link">&para;</a></h3>
<ul>
<li>The <strong>Client</strong> posts a home timeline request to the <strong>Web Server</strong></li>
<li>The <strong>Web Server</strong> forwards the request to the <strong>Read API</strong> server</li>
<li>The <strong>Read API</strong> server contacts the <strong>Timeline Service</strong>, which does the following:<ul>
<li>Gets the timeline data stored in the <strong>Memory Cache</strong>, containing tweet ids and user ids - O(1)</li>
<li>Queries the <strong>Tweet Info Service</strong> with a <a href="http://redis.io/commands/mget">multiget</a> to obtain additional info about the tweet ids - O(n)</li>
<li>Queries the <strong>User Info Service</strong> with a multiget to obtain additional info about the user ids - O(n)</li>
</ul>
</li>
</ul>
<p>REST API:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>$ curl https://twitter.com/api/v1/home_timeline?user_id=123
</span></code></pre></div>
<p>Response:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a>{
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a> &quot;user_id&quot;: &quot;456&quot;,
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a> &quot;tweet_id&quot;: &quot;123&quot;,
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a> &quot;status&quot;: &quot;foo&quot;
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a>},
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a>{
</span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a> &quot;user_id&quot;: &quot;789&quot;,
</span><span id="__span-4-8"><a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a> &quot;tweet_id&quot;: &quot;456&quot;,
</span><span id="__span-4-9"><a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a> &quot;status&quot;: &quot;bar&quot;
</span><span id="__span-4-10"><a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a>},
</span><span id="__span-4-11"><a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a>{
</span><span id="__span-4-12"><a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a> &quot;user_id&quot;: &quot;789&quot;,
</span><span id="__span-4-13"><a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a> &quot;tweet_id&quot;: &quot;579&quot;,
</span><span id="__span-4-14"><a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a> &quot;status&quot;: &quot;baz&quot;
</span><span id="__span-4-15"><a id="__codelineno-4-15" name="__codelineno-4-15" href="#__codelineno-4-15"></a>},
</span></code></pre></div>
<h3 id="use-case-user-views-the-user-timeline">Use case: User views the user timeline<a class="headerlink" href="#use-case-user-views-the-user-timeline" title="Permanent link">&para;</a></h3>
<ul>
<li>The <strong>Client</strong> posts a user timeline request to the <strong>Web Server</strong></li>
<li>The <strong>Web Server</strong> forwards the request to the <strong>Read API</strong> server</li>
<li>The <strong>Read API</strong> retrieves the user timeline from the <strong>SQL Database</strong></li>
</ul>
<p>The REST API would be similar to the home timeline, except all tweets would come from the user as opposed to the people the user is following.</p>
<h3 id="use-case-user-searches-keywords">Use case: User searches keywords<a class="headerlink" href="#use-case-user-searches-keywords" title="Permanent link">&para;</a></h3>
<ul>
<li>The <strong>Client</strong> sends a search request to the <strong>Web Server</strong></li>
<li>The <strong>Web Server</strong> forwards the request to the <strong>Search API</strong> server</li>
<li>The <strong>Search API</strong> contacts the <strong>Search Service</strong>, which does the following:<ul>
<li>Parses/tokenizes the input query, determining what needs to be searched<ul>
<li>Removes markup</li>
<li>Breaks up the text into terms</li>
<li>Fixes typos</li>
<li>Normalizes capitalization</li>
<li>Converts the query to use boolean operations</li>
</ul>
</li>
<li>Queries the <strong>Search Cluster</strong> (ie <a href="https://lucene.apache.org/">Lucene</a>) for the results:<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#under-development">Scatter gathers</a> each server in the cluster to determine if there are any results for the query</li>
<li>Merges, ranks, sorts, and returns the results</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>REST API:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>$ curl https://twitter.com/api/v1/search?query=hello+world
</span></code></pre></div>
<p>The response would be similar to that of the home timeline, except for tweets matching the given query.</p>
<h2 id="step-4-scale-the-design">Step 4: Scale the design<a class="headerlink" href="#step-4-scale-the-design" title="Permanent link">&para;</a></h2>
<blockquote>
<p>Identify and address bottlenecks, given the constraints.</p>
</blockquote>
<p><a class="glightbox" href="http://i.imgur.com/jrUBAF7.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="Imgur" src="http://i.imgur.com/jrUBAF7.png" /></a></p>
<p><strong>Important: Do not simply jump right into the final design from the initial design!</strong></p>
<p>State you would 1) <strong>Benchmark/Load Test</strong>, 2) <strong>Profile</strong> for bottlenecks 3) address bottlenecks while evaluating alternatives and trade-offs, and 4) repeat. See <a href="../scaling_aws/">Design a system that scales to millions of users on AWS</a> as a sample on how to iteratively scale the initial design.</p>
<p>It's important to discuss what bottlenecks you might encounter with the initial design and how you might address each of them. For example, what issues are addressed by adding a <strong>Load Balancer</strong> with multiple <strong>Web Servers</strong>? <strong>CDN</strong>? <strong>Master-Slave Replicas</strong>? What are the alternatives and <strong>Trade-Offs</strong> for each?</p>
<p>We'll introduce some components to complete the design and to address scalability issues. Internal load balancers are not shown to reduce clutter.</p>
<p><em>To avoid repeating discussions</em>, refer to the following <a href="https://github.com/donnemartin/system-design-primer#index-of-system-design-topics">system design topics</a> for main talking points, tradeoffs, and alternatives:</p>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#domain-name-system">DNS</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#content-delivery-network">CDN</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#load-balancer">Load balancer</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#horizontal-scaling">Horizontal scaling</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#reverse-proxy-web-server">Web server (reverse proxy)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#application-layer">API server (application layer)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#cache">Cache</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms">Relational database management system (RDBMS)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#fail-over">SQL write master-slave failover</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#master-slave-replication">Master-slave replication</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#consistency-patterns">Consistency patterns</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#availability-patterns">Availability patterns</a></li>
</ul>
<p>The <strong>Fanout Service</strong> is a potential bottleneck. Twitter users with millions of followers could take several minutes to have their tweets go through the fanout process. This could lead to race conditions with <a class="magiclink magiclink-github magiclink-mention" href="https://github.com/replies" title="GitHub User: replies">@replies</a> to the tweet, which we could mitigate by re-ordering the tweets at serve time.</p>
<p>We could also avoid fanning out tweets from highly-followed users. Instead, we could search to find tweets for highly-followed users, merge the search results with the user's home timeline results, then re-order the tweets at serve time.</p>
<p>Additional optimizations include:</p>
<ul>
<li>Keep only several hundred tweets for each home timeline in the <strong>Memory Cache</strong></li>
<li>Keep only active users' home timeline info in the <strong>Memory Cache</strong><ul>
<li>If a user was not previously active in the past 30 days, we could rebuild the timeline from the <strong>SQL Database</strong><ul>
<li>Query the <strong>User Graph Service</strong> to determine who the user is following</li>
<li>Get the tweets from the <strong>SQL Database</strong> and add them to the <strong>Memory Cache</strong></li>
</ul>
</li>
</ul>
</li>
<li>Store only a month of tweets in the <strong>Tweet Info Service</strong></li>
<li>Store only active users in the <strong>User Info Service</strong></li>
<li>The <strong>Search Cluster</strong> would likely need to keep the tweets in memory to keep latency low</li>
</ul>
<p>We'll also want to address the bottleneck with the <strong>SQL Database</strong>.</p>
<p>Although the <strong>Memory Cache</strong> should reduce the load on the database, it is unlikely the <strong>SQL Read Replicas</strong> alone would be enough to handle the cache misses. We'll probably need to employ additional SQL scaling patterns.</p>
<p>The high volume of writes would overwhelm a single <strong>SQL Write Master-Slave</strong>, also pointing to a need for additional scaling techniques.</p>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#federation">Federation</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#sharding">Sharding</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#denormalization">Denormalization</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#sql-tuning">SQL Tuning</a></li>
</ul>
<p>We should also consider moving some data to a <strong>NoSQL Database</strong>.</p>
<h2 id="additional-talking-points">Additional talking points<a class="headerlink" href="#additional-talking-points" title="Permanent link">&para;</a></h2>
<blockquote>
<p>Additional topics to dive into, depending on the problem scope and time remaining.</p>
</blockquote>
<h4 id="nosql">NoSQL<a class="headerlink" href="#nosql" title="Permanent link">&para;</a></h4>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#key-value-store">Key-value store</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#document-store">Document store</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#wide-column-store">Wide column store</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#graph-database">Graph database</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#sql-or-nosql">SQL vs NoSQL</a></li>
</ul>
<h3 id="caching">Caching<a class="headerlink" href="#caching" title="Permanent link">&para;</a></h3>
<ul>
<li>Where to cache<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#client-caching">Client caching</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#cdn-caching">CDN caching</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#web-server-caching">Web server caching</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#database-caching">Database caching</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#application-caching">Application caching</a></li>
</ul>
</li>
<li>What to cache<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#caching-at-the-database-query-level">Caching at the database query level</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#caching-at-the-object-level">Caching at the object level</a></li>
</ul>
</li>
<li>When to update the cache<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#cache-aside">Cache-aside</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#write-through">Write-through</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#write-behind-write-back">Write-behind (write-back)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#refresh-ahead">Refresh ahead</a></li>
</ul>
</li>
</ul>
<h3 id="asynchronism-and-microservices">Asynchronism and microservices<a class="headerlink" href="#asynchronism-and-microservices" title="Permanent link">&para;</a></h3>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer#message-queues">Message queues</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#task-queues">Task queues</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#back-pressure">Back pressure</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer#microservices">Microservices</a></li>
</ul>
<h3 id="communications">Communications<a class="headerlink" href="#communications" title="Permanent link">&para;</a></h3>
<ul>
<li>Discuss tradeoffs:<ul>
<li>External communication with clients - <a href="https://github.com/donnemartin/system-design-primer#representational-state-transfer-rest">HTTP APIs following REST</a></li>
<li>Internal communications - <a href="https://github.com/donnemartin/system-design-primer#remote-procedure-call-rpc">RPC</a></li>
</ul>
</li>
<li><a href="https://github.com/donnemartin/system-design-primer#service-discovery">Service discovery</a></li>
</ul>
<h3 id="security">Security<a class="headerlink" href="#security" title="Permanent link">&para;</a></h3>
<p>Refer to the <a href="https://github.com/donnemartin/system-design-primer#security">security section</a>.</p>
<h3 id="latency-numbers">Latency numbers<a class="headerlink" href="#latency-numbers" title="Permanent link">&para;</a></h3>
<p>See <a href="https://github.com/donnemartin/system-design-primer#latency-numbers-every-programmer-should-know">Latency numbers every programmer should know</a>.</p>
<h3 id="ongoing">Ongoing<a class="headerlink" href="#ongoing" title="Permanent link">&para;</a></h3>
<ul>
<li>Continue benchmarking and monitoring your system to address bottlenecks as they come up</li>
<li>Scaling is an iterative process</li>
</ul>
<hr>
<div class="md-source-file">
<small>
最后更新:
<span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-iso_date">2024-06-08</span>
</small>
</div>
</article>
</div>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12Z"/></svg>
回到页面顶部
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2023 - 2024 Tink
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
<div class="md-social">
<a href="https://github.com/squidfunk" target="_blank" rel="noopener" title="github.com" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
</a>
<a href="https://hub.docker.com/r/squidfunk/mkdocs-material/" target="_blank" rel="noopener" title="hub.docker.com" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M349.9 236.3h-66.1v-59.4h66.1v59.4zm0-204.3h-66.1v60.7h66.1V32zm78.2 144.8H362v59.4h66.1v-59.4zm-156.3-72.1h-66.1v60.1h66.1v-60.1zm78.1 0h-66.1v60.1h66.1v-60.1zm276.8 100c-14.4-9.7-47.6-13.2-73.1-8.4-3.3-24-16.7-44.9-41.1-63.7l-14-9.3-9.3 14c-18.4 27.8-23.4 73.6-3.7 103.8-8.7 4.7-25.8 11.1-48.4 10.7H2.4c-8.7 50.8 5.8 116.8 44 162.1 37.1 43.9 92.7 66.2 165.4 66.2 157.4 0 273.9-72.5 328.4-204.2 21.4.4 67.6.1 91.3-45.2 1.5-2.5 6.6-13.2 8.5-17.1l-13.3-8.9zm-511.1-27.9h-66v59.4h66.1v-59.4zm78.1 0h-66.1v59.4h66.1v-59.4zm78.1 0h-66.1v59.4h66.1v-59.4zm-78.1-72.1h-66.1v60.1h66.1v-60.1z"/></svg>
</a>
<a href="https://pypi.org/project/mkdocs-material/" target="_blank" rel="noopener" title="pypi.org" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.8 200.5c-7.7-30.9-22.3-54.2-53.4-54.2h-40.1v47.4c0 36.8-31.2 67.8-66.8 67.8H172.7c-29.2 0-53.4 25-53.4 54.3v101.8c0 29 25.2 46 53.4 54.3 33.8 9.9 66.3 11.7 106.8 0 26.9-7.8 53.4-23.5 53.4-54.3v-40.7H226.2v-13.6h160.2c31.1 0 42.6-21.7 53.4-54.2 11.2-33.5 10.7-65.7 0-108.6zM286.2 404c11.1 0 20.1 9.1 20.1 20.3 0 11.3-9 20.4-20.1 20.4-11 0-20.1-9.2-20.1-20.4.1-11.3 9.1-20.3 20.1-20.3zM167.8 248.1h106.8c29.7 0 53.4-24.5 53.4-54.3V91.9c0-29-24.4-50.7-53.4-55.6-35.8-5.9-74.7-5.6-106.8.1-45.2 8-53.4 24.7-53.4 55.6v40.7h106.9v13.6h-147c-31.1 0-58.3 18.7-66.8 54.2-9.8 40.7-10.2 66.1 0 108.6 7.6 31.6 25.7 54.2 56.8 54.2H101v-48.8c0-35.3 30.5-66.4 66.8-66.4zm-6.7-142.6c-11.1 0-20.1-9.1-20.1-20.3.1-11.3 9-20.4 20.1-20.4 11 0 20.1 9.2 20.1 20.4s-9 20.3-20.1 20.3z"/></svg>
</a>
<a href="https://fosstodon.org/@squidfunk" target="_blank" rel="noopener me" title="fosstodon.org" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
</a>
<a href="https://twitter.com/squidfunk" target="_blank" rel="noopener" title="twitter.com" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../../../../..", "features": ["announce.dismiss", "content.action.edit", "content.action.view", "content.code.annotate", "content.code.copy", "content.tooltips", "navigation.footer", "navigation.indexes", "navigation.sections", "navigation.tabs", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../../../../assets/javascripts/workers/search.f886a092.min.js", "translations": {"clipboard.copied": "\u5df2\u590d\u5236", "clipboard.copy": "\u590d\u5236", "search.result.more.one": "\u5728\u8be5\u9875\u4e0a\u8fd8\u6709 1 \u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.more.other": "\u5728\u8be5\u9875\u4e0a\u8fd8\u6709 # \u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.none": "\u6ca1\u6709\u627e\u5230\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.one": "\u627e\u5230 1 \u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.other": "# \u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.placeholder": "\u952e\u5165\u4ee5\u5f00\u59cb\u641c\u7d22", "search.result.term.missing": "\u7f3a\u5c11", "select.version": "\u9009\u62e9\u5f53\u524d\u7248\u672c"}}</script>
<script src="../../../../../assets/javascripts/bundle.94c44541.min.js"></script>
<script src="../../../../../js/print-site.js"></script>
<script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
document$.subscribe(() => { lightbox.reload() });
</script></body>
</html>