性能优化——架构篇

性能优化是程序员进阶之路上绕不开的话题。 可是这个话题实在太大,很难是一两篇文章就讲明白。 所以我打算从全局视角切入,再慢慢细化每一块的重点,希望能够帮助看到这篇文章的你简历一个清晰的知识图谱。

一个经典的问题

在前几年,很多大厂会问这样一道面试题:”你在浏览器输入 www.taobao.com 的时候,发生了什么?”。

能把这道题目回答完美非常不容易,因为这里面涉及的知识点非常多,每一个展开讨论都是一个大的课题。

在这里,我先给出一个非常非常粗粒度的答案,然后再慢慢深入细化。

DNS解析-->网络连接建立-->静态资源加载-->服务端资源获取-->页面渲染。

最简单的应用系统

最简单的应用系统

上图就是一个最简单的应用系统,买一个域名,绑定自己的服务器地址。

当用户请求你的域名时,DNS解析到服务器的ip地址,然后浏览器请求服务器获取资源,渲染页面。

优化核心的思路一——缓存

这么做最大的问题是,用户的每一次请求都是 最长路径 也就是每次都会经过浏览器到WebService再到DB,服务器的压力可想而知。

数据缓存

而我们知道,用户访问的页面其实数据都是一样的,我们没有必要每一次都去数据库获取一遍,白白增加数据库的压力。

所以,我们做的第一个优化就是建立DB的缓存。

服务端缓存

图中的 Cache 部分就是缓存一些重复查询DB的操作,减轻数据库的压力。

在做本地缓存时,还可以再拆分出Local的(基于JVM内存)缓存和Server(基于缓存服务器)缓存。

Local缓存

Local的缓存很好理解,最简单的实现就是JDK中的MAP,查到值就返回,查不到再去DB获取一遍,然后再回写缓存。

Local缓存最大的好处就是快,基于纯内存。而最大的弊端也就是他基于纯内存,这样一旦服务器重启,那么缓存也就全部失效。所以基于纯Local的缓存一旦服务器重启,数据库瞬间压力就会爆炸式增长。

缓存服务

那么如何解决这个问题呢? 答案就是缓存服务。

例如Redis和Memcache,这些缓存服务的访问也是基于纯内存的,速度非常快。而且支持 分布式 部署,即使某几台缓存服务重启也至于让整个后端服务崩溃。

静态资源缓存

一个网站或者一个APP,展现给用户的肯定不止数据,必然也包括一些例如图片、前端文件等。这些资源的特点就是几乎不会变化、而且特别占带宽。

最传统的设计图片也是放在后端服务器上的,浏览器访问图片每次都要从服务端获取,这样服务器的压力可想而知。

既然数据可以做缓存,那么这些静态资源当然也可以做缓存。

所以,解决的思路和上面的数据缓存一致,将那些几乎不会变的静态资源缓存起来。

静态资源缓存

如上图所示,静态资源可以单独发布在一个缓存服务器上,有一个前端资源缓存器管理,例如Nginx。(当然Nginx也可以做很多其他事)

优化的核心思路二——拆分

虽然摩尔定律让我们的服务器性能越来越好,但目前世界上没有任何一台服务器能扛住一个大型网站的流量。

在即使做了非常非常多的缓存优化,我们的服务器仍然扛不住用户的流量的情况下,我们只能祭出第二个思路——拆分。

拆分的思路就是用很多很多个小型的服务器来分别处理用户的请求,达到无限 横向扩展 的目的,从而达到没有理论流量上限的目标。

负载均衡

如下图所示,我们可以将一块服务都拆出一个个 然后每一个层是由N个无差别服务器组成,流量会被均匀或者按照特定规则分发到这些服务器上,从而达到减少单个服务器压力的目的。

而且这样的设计架构没有理论上的负载上限,只要你机器足够多,那么流量支持就是无限大的。

当然,这里面会引发一系列的问题,例如缓存一致性、服务一致性、数据一致性等等。

但这些都已经属于分布式相关的的课题,而且业内已经有了很多成熟的解决方案,我们本章的目的是为了从全局架构的视角去看我们在优化时应该从哪些点入手,有哪些成熟的方案。

总结

本文只是从最上层的架构视角去总结如何解决系统性能瓶颈的问题,其实图中每一个点的优化都是一个很大的课题。

但有了这一章铺垫,后面关于细分领域的优化就可以很顺畅的开展,因为你已经知道了最核心的思路和每一块的定位。

没有完美的架构和解决方案,架构和方案都是为了解决某一特定场景的问题。所以这次,我从最通用的场景切入,解释了两个最核心的思路和他们分别解决了什么样的问题。后面我会细化到每一个场景再去深入探索在那个领域下,业界又是如何做性能优化的。

Table of Contents