观《亿级流量网站架构核心技术》有感

本文的架子参考张开套的《亿级流量网站架构核心技术》这本书分为四个部分:指导原则,高可用,高并发,实践案例。这篇文章说一说前三个部分,大部份内容都是我本身的思考,书只做为参考。java

  • 指导原则
  • 高可用
    • 事前
      • 副本技术
      • 隔离技术
      • 配额技术
      • 探知技术
      • 预案
    • 事发
      • 监控和报警
    • 事中
      • 降级
      • 回滚
      • failXXX系列
    • 过后
  • 高并发
    • 提升处理速度
      • 缓存
      • 异步
    • 增长处理人手
      • 多线程
      • 扩容

指导原则

书中所列举的,里有一些可能并非原则,而是技巧。我理解的原则以下:mysql

高并发原则:web

  1. 无状态设计:由于有状态可能涉及锁操做,锁又可能致使并发的串行化。
  2. 保持合理的粒度:不管拆分仍是服务化,其实就是服务粒度控制,控制粒度为了分散请求提升并发,或为了从管理等角度提升可操性。
  3. 缓存、队列、并发等技巧在高并发设计上可供参考,但需依场景使用。

高可用原则:算法

  1. 系统的任何发布必须具备可回滚能力。
  2. 系统任何外部依赖必须准确衡量是否可降级,是否可无损降级,并提供降级开关。
  3. 系统对外暴露的接口必须配置好限流,限流值必须尽可能准确可靠。

业务设计原则:sql

  1. 安全性:防抓取,防刷单、防表单重复提交,等等等等。
  2. at least 消费,应考虑是否采用幂等设计
  3. 业务流程动态化,业务规则动态化
  4. 系统owner负责制、人员备份制、值班制
  5. 系统文档化
  6. 后台操做可追溯

以上原则只是大千世界中的一小部分,读者应当在工做学习中点滴积累。数据库

高可用

咱们先说高可用的本质诉求:高可用就是抵御不肯定性,保证系统7*24小时健康服务。关于高可用,咱们其实面对的问题就是对抗不肯定性,这个不肯定性来自四面八方。好比大地震,会致使整个机房中断,如何应对?好比负责核心系统的工程师离职了,如何应对?再好比下游接口挂了,如何应对?系统磁盘坏了,数据面临丢失风险,如何应对?我想关于上述问题的应对方式,你们在工做中或多或少都有所了解,而这个不肯定性的处理过程,就是容灾,其不一样的‘灾难’,对应不一样的容灾级别。编程

为了对抗这些不一样级别的不肯定性,就要付出不一样级别的成本,所以可用性也应是有标准的。这标准就是你们常说的N个9。随着N的增长,成本也相应增长,那如何在达到业务须要的可用性的基础上,尽可能节省成本?这也是一个值得思考的话题。除此以外,100%减去这N个9就说所谓的平均故障时间(MTBF),不少人只关心那些9,而忽略了故障处理时间,这是不应的:你的故障处理速度越快,系统的可用性才有可能越高。缓存

上面扯了一些可用性概念上的东西,下面来讲一下技巧。开涛的书中没有对可用性技巧作出一个分类,我这里则尝试使用‘事情’来分个类。这里的‘事’就是故障,分为:事前(故障发生之前)、事发(故障发生到系统或人感知到故障)、事中(故障发生到故障处理这段时间)、过后(故障结束以后)。安全

按照上述分类,不一样的阶段应有着不一样的技巧:性能优化

  1. 事前:副本、隔离、配额、提早预案、探知
  2. 事发:监控、报警
  3. 事中:降级、回滚、应急预案,failXXX系列
  4. 过后:复盘、思考、技改

事前

副本技术

大天然是副本技术当之无愧的集大成者,不管是冰河时代,仍是陨石撞击地球所带来的毁灭性打击,物种依然绵绵不绝的繁衍,这即是基因复制的做用。副本是对抗不肯定性的有力武器,把副本技术引入计算机系统,也会带来高可用性的提高。无状态服务集群即是副本的一个应用,由于没有状态,即可水平伸缩,而这些无状态服务器之间须要一层代理来统一调度管理,这便有了反向代理。当代理经过心跳检测机制检测到有一台机器出现问题时,就将其下线,其余‘副本’机器继续提供服务;存储领域也是常用副本技术的,好比OB的三地三中心五副本技术等,mysql主备切换,rabbitMQ的镜像队列,磁盘的RAID技术,各类nosql中的分区副本,等等等等,数不胜数,几乎全部保证高可用的系统都有冗余副本存在。

隔离技术

书上提到了不少种隔离:线程隔离、进程隔离、集群隔离、机房隔离、读写隔离、动静隔离、爬虫隔离、热点隔离、硬件资源隔离。在我看来,这些隔离其实就是一种,即资源隔离,不管线程、进程、硬件、机房、集群都是一种资源;动态资源和静态资源也不过是资源的一种分类;热点隔离也便是热点资源和非热点资源的隔离;读写隔离不过仅仅是资源的使用方式而已,相同的两份资源,一份用来写,一份用来读。所以,隔离的本质,其实就是对资源的独立保护。由于每一个资源都获得了独立的保护,其中一个资源出了问题,不会影响到其余资源,这就提升了总体服务的可用性。人类使用隔离术也由来已久了,从农业养殖,到股票投资,甚相当犯人的监狱,都能找到隔离术的影子。

配额技术

配额技术经过限制资源供给来保护系统,从而提升总体可用性。限流是配额技术的一种,它经过调节入口流量水位上线,来避免供给不足所致使的服务宕机。限流分为集群限流和单机限流,集群限流须要分布式基础设施配合,单机限流则不须要。大部分业务场景使用单机限流足以,特殊场景(类秒杀等)下的限流则需限制整个集群。除此以外,限流这里咱们还须要考虑几点:

  1. 如何设置合理的限流值?限流值的设定是须要通过全链路压测、妥善评估CPU容量、磁盘、内存、IO等指标与流量之间的变化关系(不必定线性关系)、结合业务预估和运维经验后,才能肯定。
  2. 对于被限流的流量如何处理?有几种处理方式,其一直接丢弃,用温和的文案提醒用户;其二,静默,俗称的无损降级,用缓存内容刷新页面;其三,蓄洪,异步回血,这通常用于事务型场景。
  3. 会不会致使误杀?单机限流会致使误杀,尤为当负载不均衡的状况下,很容易出现误杀;单机限流值设定太小也容易出现误杀的状况。

探知技术

其只用于探知系统当前可用性能力,没法切实提升系统可用性,作很差甚至还会下降系统可用性。压测和演练和最多见的探知技术 。压测分为全链路压测和单链路压测,全链路压测用于像双十一大促活动等,须要各上下游系统总体配合,单链路压测通常验证功能或作简单的单机压测提取性能指标。全链路压测的通常过程是:压测目标设定和评估,压测改造,压测脚本编写部署,压测数据准备,小流量链路验证,通知上下游系统owner,压测预热,压测,压测结果评估报告,性能优化。以上过程反复迭代,直到达到压测目标为止;演练通常按规模划分:好比城市级别的容灾演练,机房级别的容灾演练,集群规模的容灾演练(DB集群,缓存集群,应用集群等),单机级别的故障注入,预案演练等。演练的做用无需过多强调,但演练通常发生在凌晨,也须要各系统owner配合排错,着实累人,通常都是轮班去搞。

预案

预案通常分为提早预案(事前)和应急预案(事中)。提早预案提早执行,好比将系统临时从高峰模式切换成节能模式;应急预案关键时刻才执行,主要用于止血,好比一键容灾切换等。预案技术通常要配合开关使用,推预案通常也就是推开关了。除此以外,预案也可和限流、回滚、降级等相结合,并能够做为一个按期演练项目。

事发

事发是指当故障发生了到系统或人感知到故障准备处理的这段时间,核心诉求便是如何快速、准确的识别故障。

监控和报警

通常出现故障的时候,老板大多会有三问:为何才发现?为何才解决?影响有多大?即便故障影响面较大,若是能迅速止血,在作复盘的时候多少能挽回一些面子,相反若是处理不及时,即便小小的故障,均可能让你丢了饭碗。越早识别故障,就能越早解决问题,而这眼睛即是监控和报警了。监控报警耳熟能详,这里很少赘述。

事中

事中是指当故障发生时,为了保证系统可用性,咱们能够或必须作的事情。分为降级、回滚、应急预案(见上文,这里很少数了),faillXXX系列。

降级

降级的内涵丰富,咱们只从链路角度去思考。降级的本质是弃车保帅,经过临时舍弃部分功能,保证系统总体可用性。降级虽然从总体上看系统仍然可用,但因为取舍的关系,那么可知全部的降级必定是有损的。不可能有真正的无损降级,而常说的无损降级指的是用户体验无损。降级必定发生在层与层之间(上下游),要么a层临时性不调用b层,这叫作熔断,要么a层临时调用c层(c层合理性必定<b层),这叫备用链路。不管是哪种方式,都会面临一个问题:如何肯定何时降级,何时恢复?通常有两种方式,其一是人工确认,经过监控报警等反馈机制,人工识别故障,推送降级,待故障恢复后在手动回滚;其二是自适应识别,最经常使用的指标有超时时间、错误次数、限值流等等,当达到阈值时自动执行降级,恢复时自动回滚。这两种方式无需对比,它们都是常常采用的高可用技巧。除此以外,咱们还要注意降级和强弱依赖的关系。强弱依赖表示的是链路上下游之间的依赖关系,是’是否可降级‘的一种专业表述。

咱们再来看书中的一些降级的例子:①读写降级,其实是存储层和应用层之间的降级,采用备用链路切换方式,损失了一致性;②功能降级,将部分功能关闭,其实是应用层和功能模块层之间的降级,采用熔断方式,损失了部分功能。③爬虫降级,其实是搜索引擎爬虫和应用系统之间的降级,采用备用链路切换方式,将爬虫引导到静态页面,损失是引擎索引的创建和页面收录。

回滚

当执行某种变动出现故障时,最为稳妥和有效的办法就是回滚。虽然回滚行之有效,但并不简单,由于回滚有一个大前提:变动必须具备可回滚性。而让某一种变动具备可回滚的特性,是要耗费很大力气的。索性的是,大部分基础服务已经帮咱们封装好了这一特性,好比DB的事务回滚(DB事务机制),代码库回滚(GIT的文件版本控制),发布回滚(发布系统支持)等等。咱们在平常变动操做的时候,必需要肯定你的操做是否可回滚,并尽力保证全部变动都可回滚。若是不能回滚,是否能够进行热更新(好比发布应用到app store)或最终一致性补偿等额外手段保证系统高可用。

failXXX系列

当出现下游调用失败时,咱们通常有几种处理方式:

  1. failretry,即失败重试,须要配合退避时间,不然立刻重试不必定会有效果。
  2. failover,即所谓的故障转移。好比调用下游a接口失败,那么RPC的负载均衡器将会调用a接口提供方的其余机器进行重试;在好比数据库x挂了,应用自适应容灾将对x库的调用切换到y库调用,此y库便可以是faillover库(流水型业务),也能够备库(状态型业务)。
  3. failsafe,即静默,通常下游链路是弱依赖的时候,能够采用failsafe,便可和failover相结合,好比failover了3次仍是失败,那么执行failsafe。
  4. failfast,当即报错,failfast主要让工程师快速的感知问题所在,并及时进行人工干预。
  5. failback,延迟补偿(回血),通常能够采用消息队列或定时扫描等。

上面的1,2,4是属于重试策略,即书中《超时与重试》章节所讲到的重试。重试有个问题:退避间隔是多少?重试几回?通常在下游临时抖动的状况下,很短期内就能够恢复;但当下游彻底不可用,那么颇有可能重试多少次都不会成功,反而会对下游形成了更大的压力,那这种状况就应当作用熔断了。因此正确设定重试次数、选择退避时间等都是须要仔细思考的。咱们在来讲一下超时,超时只是一种预防机制,不是故障应对策略,其主要为了防止请求堆积——资源都用于等待下游请求返回了。堆积的后果自不用多说,重要的是如何选择正确的超时时间?书上只说了链路每一个部分超时时间怎么配置,殊不知道应配置多少,这是不够全面的。

过后

复盘、思考、技改。很少赘述。

高并发

若是仅是追求高可用性,这其实并不难作,试想若是一年只有一我的访问你的系统,只要这一我的访问成功,那你系统的‘’可用性‘就是100%了。可现实是,随着业务的发展,请求量会愈来愈高,进而各类系统资源得以激活,那潜在风险也会慢慢的暴露出来。所以,作系统的难点之一即是:如何在高并发的条件下,保证系统的高可用。上文已经说了一些保证高可用的技巧,这节将结合开涛的书,说说高并发。

说到这里,也给你们推荐一个交流平台:架构交流群650385180,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理、并发编程原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,相信对于已经工做和遇到技术瓶颈的码友,在这个群里必定有你须要的内容。

上图是咱们生活中常见的一个场景——排队购物。收银员就是咱们的服务,每个在队列中的顾客都是一个请求。咱们的本质诉求是让尽量多的人都在合理的等待时间内完成消费。如何作到这一点呢?其一是提升收银员的处理速度,他们处理的越快,单位时间内就能服务更多的顾客;其二是增长人手,一名收银员处理不过来,咱们就雇十名收银员,十名不够咱们就雇佣一百名(若是不计成本);其三是减小访问人数,也即分流过滤,将一些人提早过滤掉,或作活动预热(好比双十一预热),在高峰以前先知足一部分人的需求。所以,想要高并发无外乎从如下几个方面入手:

  1. 提升处理速度:缓存、异步
  2. 增长处理人手:多线程(多进程)、扩容
  3. 减小访问人数:预处理(本文不涉及)

提升处理速度

缓存

缓存之因此可以提升处理速度,是由于不一样设备的访问速度存在差别。缓存的话题能够扯几本书不带重样的。从CPU能够一直扯到客户端缓存,即从最底层一直到扯到最特近用户的一层,每一层均可能或能够有缓存的存在。咱们这里不扯这么多,只说简单服务端缓存。如今从几个不一样角度来看一下缓存:

①从效果角度。命中率越高越好吗?10万个店铺数据,缓存了1000个,命中率稳定100%,那是否是说,有99000个店铺都是长尾店铺?缓存效果评估不能单看命中率。
②从回收策略。若是把缓存当作数据库同样的存储设备去用,那就没有回收的说法了(除非重启或者宕机,不然数据依然有效);若是只存储热数据,那就有回收和替换的问题。回收有两种方式,一种是空间配额,另外一种是时间配额。替换也有几种方式,LRU,FIFO,LFU。
③从缓存使用模式角度:用户直接操做缓存和db;用户直接操做缓存,缓存帮助咱们读写DbB;
④从缓存分级角度。java堆内缓存、java堆外缓存、磁盘缓存、分布式缓存,多级缓存。
⑤从缓存使用角度。null穿透问题、惊群问题、缓存热点问题、缓存一致性问题、读写扩散问题。。。。。。
⑥更新方式。读更新、写更新、异步更新。

若是缓存集群涉及到异地多集群部署,再结合大数据量高并发业务场景,还会遇到不少更加复杂的问题,这里就不一一列举了。

异步

异步这里有几点内涵,其一是将多个同步调用变成异步并发调用,这样就将总响应时间由原来的t1+t2+t3+…..+tn变成了max(t1,t2,t3….,tn),这也叫异步编排;其二是在操做系统层面,使用asyc io以提升io处理性能;其三是将请求’转储‘,稍后异步进行处理,通常使用队列中间件。其中的异步编排,可使用CompletableFuture;异步IO通常框架都作了封装;而队列中间件则是最为经常使用的技术之一,也是咱们重点关注的对象。

业务容许延迟处理,是使用队列中间件的大前提,即非实时系统或准实时系统更适合使用。主要做用有:异步处理(增长吞吐),削峰蓄洪(保障稳定性),数据同步(最终一致性组件),系统解耦(下游无需感知订阅方)。

缓冲队列:通常使用环形缓冲队列,控制缓冲区大小。
任务队列:通常用于任务调度系统,好比线程池等,disrupter
消息队列:通常意义上的消息中间件,不一样业务场景须要的中间件能力不一样,有的须要高吞吐,有的须要支持事务,有的须要支持多客户端,有的须要支持特定协议等等等等,妄图开发一个大而全的消息队列,我的以为不如提供多种队列按需选型,以后在统一提供一个通讯中台,全面整合消息能力。
请求队列:就是处理请求的队列,有点像流程引擎,能够作一些前置后置的入队出队处理,好比限流、过滤等等
数据总线队列:好比canal,datax等数据(异构或同构)同步用的。
优先级队列:通常大根堆实现
副本队列:若是队列支持回放,副本队列有些冗余。
镜像队列:通常用于作队列系统的高可用切换的。有时候也跨集群跨机房作复制,提供更多消费者消费,增长投递能力。

队列的消费端有pull模式或者push模式的选取。pull模式能够控制进度,push模式则实时性更高一些;pull能支持单队列上的有序,push很难支持。除了消费模式,队列还有一系列其余问题请参考其余书籍,这里很少说明了。

这里在补充一点关于异步的说明。同步转异步,能够提升吞吐量;异步转同步,能够增长可靠性。

增长处理人手

多线程

多线程(多进程)技术是‘增长处理人手’技术中最容易想到的,通常咱们也普遍采用。不管是web服务容器、网关、RPC服务端、消息队列消费和发送端等等都有使用多线程技术。其优势也无需过多说明。这里咱们只说一件重要的事情,即线程数的设置问题,若是线程数太高则可能会吃光系统资源,若是太低又没法发挥多线程优点。通常设置的时候,会参考平均处理时长、并发峰值、平均并发量、阻塞率、最长可容忍响应时间、CPU核心数等等,而后作必定的运算,计算出线程数、core和max,以及阻塞队列大小。具体算法能够自行谷歌。

扩容

在无状态服务下,扩容多是迄今为止效果最明显的增长并发量的技巧之一。有临时性并发问题时,能够直接提扩容工单,立竿见影。但扩容的最大问题就是成本了,想一想动辄几万的实体机,若是只是为了支撑一个小时的大促,而日常利用率几乎为0,那确实是浪费。所以便有了弹性云,当须要扩容时,借别人机器(阿里云)用完再还回去;以及离线在线混部,充分利用资源。

从扩容方式角度讲,分为垂直扩容(scale up)和水平扩容(scale out)。垂直扩容就是增长单机处理能力,怼硬件,但硬件能力毕竟仍是有限;水平扩容说白了就是增长机器数量,怼机器,但随着机器数量的增长,单应用并发能力并不必定与其呈现线性关系, 此时就可能须要进行应用服务化拆分了。

从数据角度讲,扩容能够分为无状态扩容和有状态扩容。无状态扩容通常就是指咱们的应用服务器扩容;有状态扩容通常是指数据存储扩容,要么将一份数据拆分红不一样的多份,即sharding,要么就总体复制n份,即副本。sharding遇到的问题就是分片的可靠性,通常作转移、rehash、分片副本;副本遇到的问题是一致性性,通常作一致性算法,如paxos,raft等。

相关文章
相关标签/搜索