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.

3153 lines
84 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/README-zh-Hans/">
<link rel="icon" href="../../../../../../images/favicon.ico">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.4.4">
<title>设计推特时间轴与搜索功能 - 开发知识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="#_1" 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">
设计推特时间轴与搜索功能
</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="#_2" class="md-nav__link">
第一步:简述用例与约束条件
</a>
<nav class="md-nav" aria-label="第一步:简述用例与约束条件">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_3" class="md-nav__link">
用例
</a>
<nav class="md-nav" aria-label="用例">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_4" class="md-nav__link">
我们将把问题限定在仅处理以下用例的范围中
</a>
</li>
<li class="md-nav__item">
<a href="#_5" class="md-nav__link">
不在用例范围内的有
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_6" class="md-nav__link">
限制条件与假设
</a>
<nav class="md-nav" aria-label="限制条件与假设">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_7" class="md-nav__link">
提出假设
</a>
</li>
<li class="md-nav__item">
<a href="#_8" class="md-nav__link">
计算用量
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_9" class="md-nav__link">
第二步:概要设计
</a>
</li>
<li class="md-nav__item">
<a href="#_10" class="md-nav__link">
第三步:设计核心组件
</a>
<nav class="md-nav" aria-label="第三步:设计核心组件">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_11" class="md-nav__link">
用例:用户发表了一篇推特
</a>
</li>
<li class="md-nav__item">
<a href="#_12" class="md-nav__link">
用例:用户浏览主页时间轴
</a>
</li>
<li class="md-nav__item">
<a href="#_13" class="md-nav__link">
用例:用户浏览用户时间轴
</a>
</li>
<li class="md-nav__item">
<a href="#_14" class="md-nav__link">
用例:用户搜索关键词
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_15" class="md-nav__link">
第四步:架构扩展
</a>
</li>
<li class="md-nav__item">
<a href="#_16" class="md-nav__link">
其它要点
</a>
<nav class="md-nav" aria-label="其它要点">
<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="#_17" class="md-nav__link">
缓存
</a>
</li>
<li class="md-nav__item">
<a href="#_18" class="md-nav__link">
异步与微服务
</a>
</li>
<li class="md-nav__item">
<a href="#_19" class="md-nav__link">
通信
</a>
</li>
<li class="md-nav__item">
<a href="#_20" class="md-nav__link">
安全性
</a>
</li>
<li class="md-nav__item">
<a href="#_21" class="md-nav__link">
延迟数值
</a>
</li>
<li class="md-nav__item">
<a href="#_22" class="md-nav__link">
持续探讨
</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="_1">设计推特时间轴与搜索功能<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h1>
<p><strong>注意:这个文档中的链接会直接指向<a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引">系统设计主题索引</a>中的有关部分,以避免重复的内容。你可以参考链接的相关内容,来了解其总的要点、方案的权衡取舍以及可选的替代方案。</strong></p>
<p><strong>设计 Facebook 的 feed</strong> 与**设计 Facebook 搜索**与此为同一类型问题。</p>
<h2 id="_2">第一步:简述用例与约束条件<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2>
<blockquote>
<p>搜集需求与问题的范围。
提出问题来明确用例与约束条件。
讨论假设。</p>
</blockquote>
<p>我们将在没有面试官明确说明问题的情况下,自己定义一些用例以及限制条件。</p>
<h3 id="_3">用例<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h3>
<h4 id="_4">我们将把问题限定在仅处理以下用例的范围中<a class="headerlink" href="#_4" title="Permanent link">&para;</a></h4>
<ul>
<li>**用户**发布了一篇推特<ul>
<li>**服务**将推特推送给关注者,给他们发送消息通知与邮件</li>
</ul>
</li>
<li>**用户**浏览用户时间轴(用户最近的活动)</li>
<li>**用户**浏览主页时间轴(用户关注的人最近的活动)</li>
<li>**用户**搜索关键词</li>
<li>**服务**需要有高可用性</li>
</ul>
<h4 id="_5">不在用例范围内的有<a class="headerlink" href="#_5" title="Permanent link">&para;</a></h4>
<ul>
<li>**服务**向 Firehose 与其它流数据接口推送推特</li>
<li>**服务**根据用户的”是否可见“选项排除推特<ul>
<li>隐藏未关注者的 @回复</li>
<li>关心”隐藏转发“设置</li>
</ul>
</li>
<li>数据分析</li>
</ul>
<h3 id="_6">限制条件与假设<a class="headerlink" href="#_6" title="Permanent link">&para;</a></h3>
<h4 id="_7">提出假设<a class="headerlink" href="#_7" title="Permanent link">&para;</a></h4>
<p>普遍情况</p>
<ul>
<li>网络流量不是均匀分布的</li>
<li>发布推特的速度需要足够快速<ul>
<li>除非有上百万的关注者,否则将推特推送给粉丝的速度要足够快</li>
</ul>
</li>
<li>1 亿个活跃用户</li>
<li>每天新发布 5 亿条推特,每月新发布 150 亿条推特<ul>
<li>平均每条推特需要推送给 5 个人</li>
<li>每天需要进行 50 亿次推送</li>
<li>每月需要进行 1500 亿次推送</li>
</ul>
</li>
<li>每月需要处理 2500 亿次读取请求</li>
<li>每月需要处理 100 亿次搜索</li>
</ul>
<p>时间轴功能</p>
<ul>
<li>浏览时间轴需要足够快</li>
<li>推特的读取负载要大于写入负载<ul>
<li>需要为推特的快速读取进行优化</li>
</ul>
</li>
<li>存入推特是高写入负载功能</li>
</ul>
<p>搜索功能</p>
<ul>
<li>搜索速度需要足够快</li>
<li>搜索是高负载读取功能</li>
</ul>
<h4 id="_8">计算用量<a class="headerlink" href="#_8" title="Permanent link">&para;</a></h4>
<p><strong>如果你需要进行粗略的用量计算,请向你的面试官说明。</strong></p>
<ul>
<li>每条推特的大小:<ul>
<li><code>tweet_id</code> - 8 字节</li>
<li><code>user_id</code> - 32 字节</li>
<li><code>text</code> - 140 字节</li>
<li><code>media</code> - 平均 10 KB</li>
<li>总计: 大约 10 KB</li>
</ul>
</li>
<li>每月产生新推特的内容为 150 TB<ul>
<li>每条推特 10 KB * 每天 5 亿条推特 * 每月 30 天</li>
<li>3 年产生新推特的内容为 5.4 PB</li>
</ul>
</li>
<li>每秒需要处理 10 万次读取请求<ul>
<li>每个月需要处理 2500 亿次请求 * (每秒 400 次请求 / 每月 10 亿次请求)</li>
</ul>
</li>
<li>每秒发布 6000 条推特<ul>
<li>每月发布 150 亿条推特 * (每秒 400 次请求 / 每月 10 次请求)</li>
</ul>
</li>
<li>每秒推送 6 万条推特<ul>
<li>每月推送 1500 亿条推特 * (每秒 400 次请求 / 每月 10 亿次请求)</li>
</ul>
</li>
<li>每秒 4000 次搜索请求</li>
</ul>
<p>便利换算指南:</p>
<ul>
<li>每个月有 250 万秒</li>
<li>每秒一个请求 = 每个月 250 万次请求</li>
<li>每秒 40 个请求 = 每个月 1 亿次请求</li>
<li>每秒 400 个请求 = 每个月 10 亿次请求</li>
</ul>
<h2 id="_9">第二步:概要设计<a class="headerlink" href="#_9" title="Permanent link">&para;</a></h2>
<blockquote>
<p>列出所有重要组件以规划概要设计。</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="_10">第三步:设计核心组件<a class="headerlink" href="#_10" title="Permanent link">&para;</a></h2>
<blockquote>
<p>深入每个核心组件的细节。</p>
</blockquote>
<h3 id="_11">用例:用户发表了一篇推特<a class="headerlink" href="#_11" title="Permanent link">&para;</a></h3>
<p>我们可以将用户自己发表的推特存储在<a href="https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms">关系数据库</a>中。我们也可以讨论一下<a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-还是-nosql">究竟是用 SQL 还是用 NoSQL</a></p>
<p>构建用户主页时间轴(查看关注用户的活动)以及推送推特是件麻烦事。将特推传播给所有关注者(每秒约递送 6 万条推特)这一操作有可能会使传统的<a href="https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms">关系数据库</a>超负载。因此,我们可以使用 **NoSQL 数据库**或**内存数据库**之类的更快的数据存储方式。从内存读取 1 MB 连续数据大约要花 250 微秒,而从 SSD 读取同样大小的数据要花费 4 倍的时间,从机械硬盘读取需要花费 80 倍以上的时间。<sup><a href=https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#每个程序员都应该知道的延迟数>1</a></sup></p>
<p>我们可以将照片、视频之类的媒体存储于**对象存储**中。</p>
<ul>
<li>**客户端**向应用<a href="https://github.com/donnemartin/system-design-primer#reverse-proxy-web-server">反向代理</a>的**Web 服务器**发送一条推特</li>
<li>**Web 服务器**将请求转发给**写 API**服务器</li>
<li>**写 API**服务器将推特使用 **SQL 数据库**存储于用户时间轴中</li>
<li><strong>写 API**调用**消息输出服务</strong>,进行以下操作:<ul>
<li>查询**用户 图 服务**找到存储于**内存缓存**中的此用户的粉丝</li>
<li>将推特存储于**内存缓存**中的**此用户的粉丝的主页时间轴**中<ul>
<li>O(n) 复杂度操作: 1000 名粉丝 = 1000 次查找与插入</li>
</ul>
</li>
<li>将特推存储在**搜索索引服务**中,以加快搜索</li>
<li>将媒体存储于**对象存储**中</li>
<li>使用**通知服务**向粉丝发送推送:<ul>
<li>使用**队列**异步推送通知</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>向你的面试官告知你准备写多少代码</strong></p>
<p>如果我们用 Redis 作为**内存缓存**,那可以用 Redis 原生的 list 作为其数据结构。结构如下:</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>新发布的推特将被存储在对应用户(关注且活跃的用户)的主页时间轴的**内存缓存**中。</p>
<p>我们可以调用一个公共的 <a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest">REST API</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>返回:</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>而对于服务器内部的通信,我们可以使用 <a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc">RPC</a></p>
<h3 id="_12">用例:用户浏览主页时间轴<a class="headerlink" href="#_12" title="Permanent link">&para;</a></h3>
<ul>
<li>**客户端**向 **Web 服务器**发起一次读取主页时间轴的请求</li>
<li>**Web 服务器**将请求转发给**读取 API**服务器</li>
<li>**读取 API**服务器调用**时间轴服务**进行以下操作:<ul>
<li>从**内存缓存**读取时间轴数据,其中包括推特 id 与用户 id - O(1)</li>
<li>通过 <a href="http://redis.io/commands/mget">multiget</a> 向**推特信息服务**进行查询,以获取相关 id 推特的额外信息 - O(n)</li>
<li>通过 muiltiget 向**用户信息服务**进行查询,以获取相关 id 用户的额外信息 - 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>返回:</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="_13">用例:用户浏览用户时间轴<a class="headerlink" href="#_13" title="Permanent link">&para;</a></h3>
<ul>
<li>**客户端**向**Web 服务器**发起获得用户时间线的请求</li>
<li>**Web 服务器**将请求转发给**读取 API**服务器</li>
<li>**读取 API**从 **SQL 数据库**中取出用户的时间轴</li>
</ul>
<p>REST API 与前面的主页时间轴类似,区别只在于取出的推特是由用户自己发送而不是关注人发送。</p>
<h3 id="_14">用例:用户搜索关键词<a class="headerlink" href="#_14" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>客户端**将搜索请求发给**Web 服务器</strong></li>
<li>**Web 服务器**将请求转发给**搜索 API**服务器</li>
<li>**搜索 API**调用**搜索服务**进行以下操作:<ul>
<li>对输入进行转换与分词,弄明白需要搜索什么东西<ul>
<li>移除标点等额外内容</li>
<li>将文本打散为词组</li>
<li>修正拼写错误</li>
<li>规范字母大小写</li>
<li>将查询转换为布尔操作</li>
</ul>
</li>
<li>查询**搜索集群**(例如<a href="https://lucene.apache.org/">Lucene</a>)检索结果:<ul>
<li>对集群内的所有服务器进行查询,将有结果的查询进行<a href="https://github.com/donnemartin/system-design-primer#under-development">发散聚合Scatter gathers</a></li>
<li>合并取到的条目,进行评分与排序,最终返回结果</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>返回结果与前面的主页时间轴类似,只不过返回的是符合查询条件的推特。</p>
<h2 id="_15">第四步:架构扩展<a class="headerlink" href="#_15" title="Permanent link">&para;</a></h2>
<blockquote>
<p>根据限制条件,找到并解决瓶颈。</p>
</blockquote>
<p><a class="glightbox" href="http://i.imgur.com/MzExP06.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="Imgur" src="http://i.imgur.com/MzExP06.png" /></a></p>
<p><strong>重要提示:不要从最初设计直接跳到最终设计中!</strong></p>
<p>现在你要 1) <strong>基准测试、负载测试</strong>。2) **分析、描述**性能瓶颈。3) 在解决瓶颈问题的同时评估替代方案、权衡利弊。4) 重复以上步骤。请阅读<a href="../../scaling_aws/">「设计一个系统,并将其扩大到为数以百万计的 AWS 用户服务」</a> 来了解如何逐步扩大初始设计。</p>
<p>讨论初始设计可能遇到的瓶颈及相关解决方案是很重要的。例如加上一个配置多台 **Web 服务器**的**负载均衡器**是否能够解决问题?**CDN**呢?**主从复制**呢?它们各自的替代方案和需要**权衡**的利弊又有什么呢?</p>
<p>我们将会介绍一些组件来完成设计,并解决架构扩张问题。内置的负载均衡器将不做讨论以节省篇幅。</p>
<p><strong>为了避免重复讨论</strong>,请参考<a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引">系统设计主题索引</a>相关部分来了解其要点、方案的权衡取舍以及可选的替代方案。</p>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#域名系统">DNS</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#负载均衡器">负载均衡器</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#水平扩展">水平拓展</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#反向代理web-服务器">反向代理web 服务器)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#应用层">API 服务(应用层)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#缓存">缓存</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#关系型数据库管理系统rdbms">关系型数据库管理系统 (RDBMS)</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#故障切换">SQL 故障主从切换</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#主从复制">主从复制</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#一致性模式">一致性模式</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#可用性模式">可用性模式</a></li>
</ul>
<p>**消息输出服务**有可能成为性能瓶颈。那些有着百万数量关注着的用户可能发一条推特就需要好几分钟才能完成消息输出进程。这有可能使 @回复 这种推特时出现竞争条件,因此需要根据服务时间对此推特进行重排序来降低影响。</p>
<p>我们还可以避免从高关注量的用户输出推特。相反,我们可以通过搜索来找到高关注量用户的推特,并将搜索结果与用户的主页时间轴合并,再根据时间对其进行排序。</p>
<p>此外,还可以通过以下内容进行优化:</p>
<ul>
<li>仅为每个主页时间轴在**内存缓存**中存储数百条推特</li>
<li>仅在**内存缓存**中存储活动用户的主页时间轴<ul>
<li>如果某个用户在过去 30 天都没有产生活动,那我们可以使用 **SQL 数据库**重新构建他的时间轴<ul>
<li>使用**用户 图 服务**来查询并确定用户关注的人</li>
<li><strong>SQL 数据库**中取出推特,并将它们存入**内存缓存</strong></li>
</ul>
</li>
</ul>
</li>
<li>仅在**推特信息服务**中存储一个月的推特</li>
<li>仅在**用户信息服务**中存储活动用户的信息</li>
<li>**搜索集群**需要将推特保留在内存中,以降低延迟</li>
</ul>
<p>我们还可以考虑优化 <strong>SQL 数据库</strong> 来解决一些瓶颈问题。</p>
<p>**内存缓存**能减小一些数据库的负载,靠 **SQL Read 副本**已经足够处理缓存未命中情况。我们还可以考虑使用一些额外的 SQL 性能拓展技术。</p>
<p>高容量的写入将淹没单个的 **SQL 写主从**模式,因此需要更多的拓展技术。</p>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#联合">联合</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#分片">分片</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#非规范化">非规范化</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-调优">SQL 调优</a></li>
</ul>
<p>我们也可以考虑将一些数据移至 <strong>NoSQL 数据库</strong></p>
<h2 id="_16">其它要点<a class="headerlink" href="#_16" title="Permanent link">&para;</a></h2>
<blockquote>
<p>是否深入这些额外的主题,取决于你的问题范围和剩下的时间。</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/blob/master/README-zh-Hans.md#键-值存储">键-值存储</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#文档类型存储">文档类型存储</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#列型存储">列型存储</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#图数据库">图数据库</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-还是-nosql">SQL vs NoSQL</a></li>
</ul>
<h3 id="_17">缓存<a class="headerlink" href="#_17" title="Permanent link">&para;</a></h3>
<ul>
<li>在哪缓存<ul>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#客户端缓存">客户端缓存</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#cdn-缓存">CDN 缓存</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#web-服务器缓存">Web 服务器缓存</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#数据库缓存">数据库缓存</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#应用缓存">应用缓存</a></li>
</ul>
</li>
<li>什么需要缓存<ul>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#数据库查询级别的缓存">数据库查询级别的缓存</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#对象级别的缓存">对象级别的缓存</a></li>
</ul>
</li>
<li>何时更新缓存<ul>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#缓存模式">缓存模式</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#直写模式">直写模式</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#回写模式">回写模式</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#刷新">刷新</a></li>
</ul>
</li>
</ul>
<h3 id="_18">异步与微服务<a class="headerlink" href="#_18" title="Permanent link">&para;</a></h3>
<ul>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#消息队列">消息队列</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#任务队列">任务队列</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#背压">背压</a></li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#微服务">微服务</a></li>
</ul>
<h3 id="_19">通信<a class="headerlink" href="#_19" title="Permanent link">&para;</a></h3>
<ul>
<li>可权衡选择的方案:<ul>
<li>与客户端的外部通信 - <a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest">使用 REST 作为 HTTP API</a></li>
<li>服务器内部通信 - <a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc">RPC</a></li>
</ul>
</li>
<li><a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#服务发现">服务发现</a></li>
</ul>
<h3 id="_20">安全性<a class="headerlink" href="#_20" title="Permanent link">&para;</a></h3>
<p>请参阅<a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#安全">「安全」</a>一章。</p>
<h3 id="_21">延迟数值<a class="headerlink" href="#_21" title="Permanent link">&para;</a></h3>
<p>请参阅<a href="https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#每个程序员都应该知道的延迟数">「每个程序员都应该知道的延迟数」</a></p>
<h3 id="_22">持续探讨<a class="headerlink" href="#_22" title="Permanent link">&para;</a></h3>
<ul>
<li>持续进行基准测试并监控你的系统,以解决他们提出的瓶颈问题。</li>
<li>架构拓展是一个迭代的过程。</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>