learn.lianglianglee.com/专栏/架构设计面试精讲/18 如何从架构师角度回答怎么应对千万级流量的问题?.md.html
2022-05-11 18:52:13 +08:00

709 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>18 如何从架构师角度回答怎么应对千万级流量的问题?.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/架构设计面试精讲/00 开篇词 中高级研发面试,逃不开架构设计这一环.md">00 开篇词 中高级研发面试,逃不开架构设计这一环.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/01 研发工程师想提升面试竞争力,该具备这三个技术认知.md">01 研发工程师想提升面试竞争力,该具备这三个技术认知.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/02 研发工程师如何用架构师视角回答架构设计方案?.md">02 研发工程师如何用架构师视角回答架构设计方案?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/03 面试官如何考察与 CAP 有关的分布式理论?.md">03 面试官如何考察与 CAP 有关的分布式理论?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/04 亿级商品存储下,如何深度回答分布式系统的原理性问题?.md">04 亿级商品存储下,如何深度回答分布式系统的原理性问题?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/05 海量并发场景下,如何回答分布式事务一致性问题?.md">05 海量并发场景下,如何回答分布式事务一致性问题?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/06 分布式系统中,如何回答锁的实现原理?.md">06 分布式系统中,如何回答锁的实现原理?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/07 RPC如何在面试中展现出“造轮子”的能力.md">07 RPC如何在面试中展现出“造轮子”的能力.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/08 MQ如何回答消息队列的丢失、重复与积压问题.md">08 MQ如何回答消息队列的丢失、重复与积压问题.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/08 案例串联 如何让系统抗住双十一的预约抢购活动?.md">08 案例串联 如何让系统抗住双十一的预约抢购活动?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/09 如何回答 MySQL 的索引原理与优化问题?.md">09 如何回答 MySQL 的索引原理与优化问题?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/10 如何回答 MySQL 的事务隔离级别和锁的机制?.md">10 如何回答 MySQL 的事务隔离级别和锁的机制?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/11 读多写少MySQL 如何优化数据查询方案?.md">11 读多写少MySQL 如何优化数据查询方案?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/12 写多读少MySQL 如何优化数据存储方案?.md">12 写多读少MySQL 如何优化数据存储方案?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/13 缓存原理:应对面试你要掌握 Redis 哪些原理?.md">13 缓存原理:应对面试你要掌握 Redis 哪些原理?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/14 缓存策略:面试中如何回答缓存穿透、雪崩等问题?.md">14 缓存策略:面试中如何回答缓存穿透、雪崩等问题?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/15 如何向面试官证明你做的系统是高可用的?.md">15 如何向面试官证明你做的系统是高可用的?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/16 如何从架构师角度回答系统容错、降级等高可用问题?.md">16 如何从架构师角度回答系统容错、降级等高可用问题?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/17 如何向面试官证明你做的系统是高性能的?.md">17 如何向面试官证明你做的系统是高性能的?.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/架构设计面试精讲/18 如何从架构师角度回答怎么应对千万级流量的问题?.md">18 如何从架构师角度回答怎么应对千万级流量的问题?.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/19 彩蛋 互联网架构设计面试,你需要掌握的知识体系.md">19 彩蛋 互联网架构设计面试,你需要掌握的知识体系.md.html</a>
</li>
<li>
<a href="/专栏/架构设计面试精讲/结束语 程序员的道、术、势.md">结束语 程序员的道、术、势.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>18 如何从架构师角度回答怎么应对千万级流量的问题?</h1>
<p>上一讲,我带你学习了“如何评估系统的性能指标”以及“如何分析系统的性能瓶颈”,今天我们继续上一讲的话题,来解答“如何设计高性能的架构”。</p>
<p>我会从两方面出发,带你看一看在面试中遇到高性能架构设计问题时,初中级研发工程师和高级研发工程师不同的回答思路。</p>
<h3>高性能设计中的“术”</h3>
<p>学完上一讲后,你应该知道自己要从系统全链路的视角,从前端请求到后端服务评估各环节的性能指标,那么对于系统性能的优化,你依然要从全链路的视角上进行高性能的设计。</p>
<h4>前端优化</h4>
<p>前端的优化主要有三个环节:<strong>减少请求次数</strong><strong>页面静态化</strong><strong>边缘计算</strong></p>
<p>减少请求次数:减少前端脚本与后端服务的请求次数,有三种方案。</p>
<ul>
<li><strong>增加缓存控制</strong>:前端研发同学经常会设置 HTML 的缓存控制头部Cache-Control 头),这样浏览器在请求同一个文件时,只访问本地保存的资源副本,从而加速文件的访问速度。</li>
<li><strong>减少图像的请求次数</strong>:你可能经常会发现,大部分网站会将所有用到的多张图片拼成一张,这样多张图片只需要下载一次,然后再通过 CSS 中的 background-image 和 background-position 来定位目标位置选择显示哪一张图片。</li>
<li><strong>减少脚本的请求次数</strong>:通用的做法就是 CSS 压缩和 JavaScript 压缩,将多个文件压缩成一个,目的是减少传输文件的大小,而更重要的是减少请求数。</li>
</ul>
<p>而页面静态化就是缓存的一种方式,相当于把整个页面元素缓存起来,那么缓存在哪里呢?</p>
<p>通常是将页面文件事先存储在 CDN 节点中,比如将商品详情页做静态化,就是将商品详情页的页面元素存储在 CDN 节点,然后所有请求就可以直接以由 CDN 来提供服务,就不会到达后端服务了,就减少了对后端服务的压力。</p>
<p>边缘计算,被很多人提及,原因是大数据处理的实时性越来越高,由集中式的服务系统提供实时性的计算能力捉襟见肘,所以很多大厂开始将计算能力放到距离用户最近的 CDN 节点中,这就要求原有的 CDN 节点不只作为静态资源文件的缓存,而是要提供可以定制化的计算能力。</p>
<p>这部分内容会涉及一些新的概念,比如无服务架构 Serverless、BaaS、FaaS在面试中不要求候选人必须掌握但它会是你的加分项。</p>
<h4>后端优化</h4>
<p>后端环节的性能问题,可以从<strong>基础设施层面、网络层面、架构层面</strong>三个角度进行考量,为了帮助你记忆,我总结了一张脑图给你参考。</p>
<p><img src="assets/Cgp9HWA72nKAYPRvAANwIbvVsWI066.png" alt="后端性能优化.png" /></p>
<p>比如网络层面可以考虑网络专线、CDN 优化;架构层面可以考虑动静分离、集群优化、数据隔离、服务拆分、异步驱动、负载均衡等方案。</p>
<p>以上就是高性能架构设计中的技术点,初中级研发工程师要能知道系统的性能瓶颈在哪儿,以及如何优化,但高级研发工程师,不能只停留掌握技术点上,而是要有自己对技术的理解(例如下面的例子)。接下来,我就通过讲解自己对高性能的认知,帮你了解并培养自己对于技术的思考。</p>
<h3>高性能设计中的“道”</h3>
<p>你在设计高性能系统架构时,首先是清楚认知系统的硬性性能指标,举个例子。</p>
<ul>
<li><strong>指标需求</strong>:我们要保证系统的 TP 99 为 2s</li>
<li><strong>表面意思</strong>:系统要保证 99% 的请求的响应时间都在 2s 内;</li>
<li><strong>深层意思</strong>:对有经验的架构师来说,这样的需求其实是不明确的,任何系统都有自己的承载能力范围,换句话说就是在并发用户数限定范围之内,一定要保证系统的 TP 99 = 2s例如“我们要保证系统并发数在 100 万用户内的时候TP 99 为 2s”对于系统设计者而言要清楚系统有所能有所不能。</li>
</ul>
<p>所以,对一个架构师来说,要设计一个高性能的架构,至少要有以下四个系统设计的思考步骤。</p>
<ul>
<li><strong>明确指标:</strong> 比如当系统小于 100 万并发用户时,要保证系统的 TP 99 = 2s 。</li>
<li><strong>保护系统:</strong> 当系统的并发用户数量超过 100 万,要做到保证有 100 万用户的 TP 99 = 2s ,然后保护系统,并拒绝其他用户的连接请求。</li>
<li><strong>用户体验:</strong> 为了用户体验,要给系统承载容量外的用户提供优雅的体验,比如服务器排队机制,并附加具体、明确的信息提示。</li>
<li><strong>快速扩容:</strong> 这一步很容易被一些同学忽略,如今系统的性能指标还有一点就是贵在快速反应,比如能承诺出现流量压力时,可以在 3 分钟内完成扩容,并保证扩容后能承载的并发用户数量的 TP 99 = 2s。</li>
</ul>
<p>在明确了性能指标之后,高性能架构的落地工作,可以分为以下三个关键技术点。</p>
<ul>
<li><strong>做好系统限流:</strong> 通过流量控制来保证系统的稳定性。当实际并发压力超过系统性能设计指标的时候,就拒绝新的请求的连接,让用户进行排队。</li>
<li><strong>做好快速扩容:</strong> 对于扩容能力,一般要储备额外的计算资源,用于不时之需,也就是事先通过预估流出一部分资源池。</li>
</ul>
<p>有的同学可能会疑惑,既然有多余的资源为什么不提前扩容呢?这是出于对 IT 成本的考虑,作为系统设计者也要把成本作为系统的设计原则之一。</p>
<p>另一个关键因素是系统的扩容速度。这是在当今互联网软件中非常重要的系统能力之一了,就算架构设计的不够优雅,但如果响应够快,也是能解决问题。</p>
<ul>
<li><strong>做好系统优化:</strong> 就是我在上面讲的前后端优化的技术点,我要再补充一点,对系统设计者来说,性能设计要贯穿于系统建设的始终。以一个系统的研发管理过程为例,内容大致包括需求阶段、设计阶段、研发阶段、测试阶段、上线阶段、运行阶段</li>
</ul>
<p>对于性能设计(不仅仅是性能设计,所有非功能性的设计)要在项目的各阶段都进行考虑,以便根据项目过程的推进随时进行调整和优化。</p>
<h3>总结</h3>
<p><strong>技术行业发展到今天,很多技术上的问题都不存在挑战了,所谓的高性能架构设计,也仅仅变成了一种标准化的应对流程</strong></p>
<p>你要做的就是将业务问题抽象成一个技术问题比如具体到数据库设计、缓存设计、队列设计、线程设计等技术细节然后不管你通过什么渠道Google 也好,问同事也好,或者购买付费知识也好,都能找到技术的应对方案。</p>
<p>而对于面试,你的答题思路应该是这样的:</p>
<ul>
<li>先落实到技术上,比如结合业务场景,识别系统最关键的服务,然后针对性地为关键服务进行性能设计与测试,确保关键服务没有问题,然后为非关键服务提供降级和熔断处理方案。</li>
<li>再深化自己对于技术的理解,你要记住,任何复杂问题都可以按时间(系统建设周期)和空间(系统设计分层)拆解为简单的问题,然后逐一攻克,这样你才能有的放矢,这其中体现出来的思维能力才是每一个技术人的安身立命之本。</li>
</ul>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/架构设计面试精讲/17 如何向面试官证明你做的系统是高性能的?.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/架构设计面试精讲/19 彩蛋 互联网架构设计面试,你需要掌握的知识体系.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"7099792928843cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>