精华内容
下载资源
问答
  • 并发系统设计

    千次阅读 2020-05-03 00:16:35
    并发系统设计 高并发通用设计方法 Scale-out(横向扩展) 分而治之是一种常见的高并发系统设计方法,采用分布式部署的方式把流量分流开,让每个服务器都承担一部分并发和流量。 Scale-up(纵向扩展) 通过购买性能...

    高并发系统设计

    高并发通用设计方法

    Scale-out(横向扩展)

    分而治之是一种常见的高并发系统设计方法,采用分布式部署的方式把流量分流开,让每个服务器都承担一部分并发和流量。

    Scale-up(纵向扩展)

    通过购买性能更好的硬件来提升系统的并发处理能力,比方说目前系统 4 核 4G 每秒可以处理 200 次请求,那么如果要处理 400 次请求呢?很简单,我们把机器的硬件提升到 8 核 8G(硬件资源的提升可能不是线性的,这里仅为参考)。

    缓存

    使用缓存来提高系统的性能,就好比用“拓宽河道”的方式抵抗高并发大流量的冲击

    异步

    在某些场景下,未处理完成之前我们可以让请求先返回,在数据准备好之后再通知请求方,这样可以在单位时间内处理更多的请求

    什么是同步

    以方法调用为例,同步调用代表调用方要阻塞等待被调用方法中的逻辑执行完成。这种方式下,当被调用方法响应时间较长时,会造成调用方长久的阻塞,在高并发下会造成整体系统性能下降甚至发生雪崩。

    什么是异步

    异步调用恰恰相反,调用方不需要等待方法逻辑执行完成就可以返回执行其他的逻辑,在被调用方法执行完毕后再通过回调、事件通知等方式将结果反馈给调用方

    指导原则

    高并发原则

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

    高可用原则

    本质诉求:高可用就是抵御不确定性,保证系统7*24小时健康服务

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

    业务设计原则

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

    分层架构

    软件架构分层在软件工程中是一种常见的设计方式,它是将整体系统拆分成 N 个层次,每个层次有独立的职责,多个层次协同提供完整的功能

    “MVC”(Model-View-Controller)架构。它将整体的系统分成了 Model(模型),View(视图)和 Controller(控制器)三个层次

    另外一种常见的分层方式是将整体架构分为表现层、逻辑层和数据访问层

    • 表现层:展示数据结果和接受用户指令的,是最靠近用户的一层
    • 逻辑层:复杂业务的具体实现
    • 数据访问层:则是主要处理和存储之间的交互

    分层有什么好处

    • 分层的设计可以简化系统设计,让不同的人专注做某一层次的事情
    • 分层之后可以做到很高的复用
    • 分层架构可以让我们更容易做横向扩展

    如何来做系统分层

    参照阿里发布的《阿里巴巴 Java 开发手册 v1.4.0(详尽版)》
    在这里插入图片描述

    分层架构中的每一层的作用

    • 终端显示层:各端模板渲染并执行显示的层。当前主要是 Velocity 渲染,JS 渲染, JSP 渲染,移动端展示等
    • 开放接口层:将 Service 层方法封装成开放接口,同时进行网关安全控制和流量控制等
    • Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等
    • Service 层:业务逻辑层。Manager 层:通用业务处理层。这一层主要有两个作用,其一,你可以将原先 Service 层的一些通用能力下沉到这一层,比如与缓存和存储交互策略,中间件的接入;其二,你也可以在这一层封装对第三方接口的调用,比如调用支付服务,调用审核服务等
    • DAO 层:数据访问层,与底层 MySQL、Oracle、HBase 等进行数据交互。外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。

    在这个分层架构中主要增加了 Manager 层,它与 Service 层的关系是:Manager 层提供原子的服务接口,Service 层负责依据业务逻辑来编排原子接口。以上面的例子来说,Manager 层提供创建用户和获取用户信息的接口,而 Service 层负责将这两个接口组装起来。这样就把原先散布在表现层的业务逻辑都统一到了 Service 层,每一层的边界就非常清晰了

    如何提升系统性能

    高并发系统设计的三大目标:高性能、高可用、可扩展

    性能优化原则

    • 首先,性能优化一定不能盲目,一定是问题导向的。脱离了问题,盲目地提早优化会增加系统的复杂度,浪费开发人员的时间,也因为某些优化可能会对业务上有些折中的考虑,所以也会损伤业务。
    • 其次,性能优化也遵循八二原则,即你可以用 20% 的精力解决 80% 的性能问题。所以我们在优化过程中一定要抓住主要矛盾,优先优化主要的性能瓶颈点。
    • 再次,性能优化也要有数据支撑。在优化过程中,你要时刻了解你的优化让响应时间减少了多少,提升了多少的吞吐量。最后,性能优化的过程是持续的。高并发的系统通常是业务逻辑相对复杂的系统,那么在这类系统中出现的性能问题通常也会有多方面的原因。
    • 因此,我们在做性能优化的时候要明确目标,比方说,支撑每秒 1 万次请求的吞吐量下响应时间在 10ms,那么我们就需要持续不断地寻找性能瓶颈,制定优化方案,直到达到目标为止

    性能的度量指标

    平均值

    平均值是把这段时间所有请求的响应时间数据相加,再除以总请求数。

    最大值

    请求响应时间最长的值

    分位值

    分位值有很多种,比如 90 分位、95 分位、75 分位。以 90 分位为例,我们把这段时间请求的响应时间从小到大排序,假如一共有 100 个请求,那么排在第 90 位的响应时间就是 90 分位值。分位值排除了偶发极慢请求对于数据的影响,能够很好地反应这段时间的性能情况,分位值越大,对于慢请求的影响就越敏感。

    高并发下的性能优化

    • 提高系统的处理核心数
    • 减少单次任务响应时间

    系统怎样做到高可用

    可用性的度量

    MTBF 和 MTTR

    • MTBF(Mean Time Between Failure)是平均故障间隔的意思,代表两次故障的间隔时间,也就是系统正常运转的平均时间。这个时间越长,系统稳定性越高
    • MTTR(Mean Time To Repair)表示故障的平均恢复时间,也可以理解为平均故障时间。这个值越小,故障对于用户的影响越小。可用性与 MTBF 和 MTTR 的值息息相关,

    我们可以用下面的公式表示它们之间的关系:Availability = MTBF / (MTBF + MTTR)

    高可用系统设计的思路

    高可用的本质诉求:高可用就是抵御不确定性,保证系统7*24小时健康服务

    高可用系统不同的阶段应有着不同的技巧:

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

    系统设计

    负载均衡
    • 前端服务器的负载均衡: 用户流量应该最优地分布于多个网络链路上、多个数据中心中、以及多台服务器上。最优通常值得是: 最小化用户的请求延迟;低于带宽的95线峰值;基于可用服务容量平衡流量;
    • 数据中心内部的负载均衡: 在理想情况下,某个服务的负载会完全均匀地分发给所有的后端任务。在
      任何时刻,最忙和最不忙的节点永远消耗同样数量的CPU
    限流

    返回低质量的结果,提供有损服务。在最差的情况,妥善的限流来保证服务本身稳定。

    重试

    当请求返回错误(例:配额不足、超时、内部错误等),对于后端部分节点过载的情况下,倾向于立刻重试,需要留意重试带来的流量放大:

    超时
    • 进程内超时控制
    • 跨进程超时控制: 超时传递和配额
    应对连锁故障

    系统运维

    灰度发布、故障演练

    池化技术:如何减少频繁创建数据库连接的性能损耗

    这是一种常见的软件设计思想,叫做池化技术,它的核心思想是空间换时间,期望使用预先创建好的对象来减少频繁创建对象的性能开销,同时还可以对对象进行统一的管理,降低了对象的使用的成本,总之是好处多多。不过,池化技术也存在一些缺陷,比方说存储池子中的对象肯定需要消耗多余的内存,如果对象没有被频繁使用,就会造成内存上的浪费。再比方说,池子中的对象需要在系统启动的时候就预先创建完成,这在一定程度上增加了系统启动时间。可这些缺陷相比池化技术的优势来说就比较微不足道了,只要我们确认要使用的对象在创建时确实比较耗时或者消耗资源,并且这些对象也确实会被频繁地创建和销毁,我们就可以使用池化技术来优化。

    用连接池预先建立数据库连接

    数据库连接池有两个最重要的配置:最小连接数和最大连接数,它们控制着从连接池中获取连接的流程:

    • 如果当前连接数小于最小连接数,则创建新的连接处理数据库请求;
    • 如果连接池中有空闲连接则复用空闲连接;
    • 如果空闲池中没有连接并且当前连接数小于最大连接数,则创建新的连接处理请求;
    • 如果当前连接数已经大于等于最大连接数,则按照配置中设定的时间(C3P0 的连接池配置是 checkoutTimeout)等待旧的连接可用;
    • 如果等待超过了这个设定时间则向用户抛出错误

    用线程池预先创建线程

    数据库优化方案

    主从分离

    主从读写分离

    主从读写分离有两个技术上的关键点:

    • 一个是数据的拷贝,我们称为主从复制;
    • 在主从分离的情况下,我们如何屏蔽主从分离带来的访问数据库方式的变化,让开发同学像是在使用单一数据库一样
    主从复制

    在这里插入图片描述

    Mysql主从复制的过程

    Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
    Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置。
    Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master从何处开始读取日志。
    Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。

    主从复制也有一些缺陷,除了带来了部署上的复杂度,还有就是会带来一定的主从同步的延迟,这种延迟有时候会对业务产生一定的影响。这个问题解决的思路有很多,核心思想就是尽量不去从库中查询信息.

    • 第一种方案是数据的冗余
    • 第二种方案是使用缓存
    • 最后一种方案是查询主库

    写入数据量增加时,如何实现分库分表

    如何对数据库做垂直拆分

    分库分表是一种常见的将数据分片的方式,它的基本思想是依照某一种策略将数据尽量平均地分配到多个数据库节点或者多个表中。

    垂直拆分的原则一般是按照业务类型来拆分,核心思想是专库专用,将业务耦合度比较高的表拆分到单独的库中。

    如何对数据库做水平拆分

    和垂直拆分的关注点不同,垂直拆分的关注点在于业务相关性,而水平拆分指的是将单一数据表按照某一种规则拆分到多个数据库和多个数据表中,关注点在数据的特点

    拆分方式
    • 按照某一个字段的哈希值做拆分
    • 按照某一个字段的区间来拆分

    NoSQL:在高并发场景下,数据库和NoSQL如何做到互补

    对于存储服务来说,我们一般会从两个方面对它做改造:

    • 提升它的读写性能,尤其是读性能
    • 增强它在存储上的扩展能力

    NoSQL 数据库是如何做到与关系数据库互补的

    • 使用 NoSQL 提升写入性能

    MySQL 的 InnoDB 存储引擎来说,更新 binlog、redolog、undolog 都是在做顺序 IO,而更新 datafile 和索引文件则是在做随机 IO,而为了减少随机 IO 的发生,关系数据库已经做了很多的优化,比如说写入时先写入内存,然后批量刷新到磁盘上,但是随机 IO 还是会发生。

    NoSQL 数据库是怎么解决这个问题的呢?绝大部分NoSQL 使用基于 LSM 树(Log-Structured Merge Tree)的存储引擎避免随机IO

    • 使用 NoSQL 提升扩展性
      • 副本集:理解为备份
      • 分片: 理解为分库分表
      • 负载均衡: 发现 分片 之间数据分布不均匀,会对数据做重新的分配,最终让不同 Server 的数据可以尽量的均衡。当我们的 Server 存储空间不足需要扩容时,数据会自动被移动到新的 Server 上,减少了数据迁移和验证的成本

    缓存设计

    缓存,是一种存储数据的组件,它的作用是让对数据的请求更快地返回

    缓存的使用姿势(一):如何选择缓存的读写策略

    Cache Aside 策略

    • 读策略的步骤是:
      • 从缓存中读取数据;如果缓存命中,则直接返回数据;
      • 如果缓存不命中,则从数据库中查询数据;查询到数据后,将数据写入到缓存中,并且返回给用户
    • 写策略的步骤是:
      • 更新数据库中的记录;
      • 删除缓存记录

    (读穿 / 写穿)策略

    核心原则是用户只与缓存打交道,由缓存和数据库通信,写入或者读取数据

    在这里插入图片描述

    缓存的使用姿势(二):缓存如何做到高可用

    客户端方案

    在客户端配置多个缓存的节点,通过缓存写入和读取算法策略来实现分布式,从而提高缓存的可用性。

    • 写入数据时,需要把被写入缓存的数据分散到多个节点中,即进行数据分片;
    • 读数据时,可以利用多组的缓存来做容错,提升缓存系统的可用性。关于读数据,这里可以使用主从和多副本两种策略,两种策略是为了解决不同的问题而提出的。
    缓存数据如何分片

    分片算法常见的就是 Hash 分片算法和一致性 Hash 分片算法两种

    • Hash 分片算法:对缓存的 Key 做哈希计算,然后对总的缓存节点个数取余
    • 一致性 Hash 分片算法: 将整个哈希值空间组织成一个虚拟的圆环
    主从机制

    主从机制

    多副本

    在缓存前面再加一次缓存,形成多副本

    中间代理层方案

    在应用代码和缓存节点之间增加代理层,客户端所有的写入和读取的请求都通过代理层,而代理层中会内置高可用策略,帮助提升缓存系统的高可用

    服务端方案

    Redis 2.4 版本后提出的 Redis Sentinel 方案

    缓存的使用姿势

    缓存清理策略

    • 根据过期时间,清理最长时间没用过的
    • 根据过期时间,清理即将过期的
    • 根据过期时间,任意清理一个
    • 无论是否过期,随机清理
    • 无论是否过期,根据LRU原则清理
      • LRU:就是Least Recently Used,最近最久未使用过。这个原则的思想是:如果一个数据在最近一段时间没有被访问到,那么在将来他被访问的可能性也很小。LRU是在操作系统中很常见的一种原则,比如内存的页面置换算法(也包括FIFO,LFU等),对于LRU的实现,还是非常有技巧的

    缓存穿透了怎么办

    • 回种空值

    • 布隆过滤器: 简单理解为 HASH + 数组

      • 先查布隆过滤器,如果不存在就直接返回空值,而不需要继续查询数据库和缓存,这样就可以极大地减少异常查询带来的缓存穿透

    CDN:静态资源如何加速

    • DNS 技术是 CDN 实现中使用的核心技术,可以将用户的请求映射到 CDN 节点上;
    • DNS 解析结果需要做本地缓存,降低 DNS 解析过程的响应时间;
    • GSLB 可以给用户返回一个离着他更近的节点,加快静态资源的访问速度。

    消息队列

    消息队列主要作用:削峰填谷、解耦合、异步

    • 削峰填谷是消息队列最主要的作用,但是会造成请求处理的延迟
    • 解耦合可以提升你的整体系统的鲁棒性
    • 异步处理是提升系统性能的神器,但需要分清同步流程和异步流程的边界,同时消息存在着丢失的风险,我们需要考虑如何确保消息一定到达

    如何保证消息仅仅被消费一次

    • 消息的丢失可以通过生产端的重试、消息队列配置集群模式以及消费端合理处理消费进度三种方式来解决;为了解决消息的丢失通常会造成性能上的问题以及消息的重复问题;
    • 通过保证消息处理的幂等性可以解决消息的重复问题。
      • 使用唯一 ID 保证消息唯一性

    消息队列:如何降低消息队列系统中消息的延迟

    • 优化消费代码提升性能
    • 增加消费者的数量

    系统架构:每秒1万次请求的系统要做服务化拆分吗

    什么时候做系统拆分:

    • 系统中使用的资源出现扩展性问题,尤其是数据库的连接数出现瓶颈
    • 大团队共同维护一套代码,带来研发效率的降低和研发成本的提升
    • 系统部署成本越来越高

    微服务架构:微服务化后系统架构要如何改造

    微服务拆分的原则

    • 原则一:做到单一服务内部功能的高内聚和低耦合。也就是说每个服务只完成自己职责之内的任务,对于不是自己职责的功能交给其它服务来完成。说起来你可能觉得理所当然对这一点不屑一顾,但很多人在实际开发中,经常会出现一些问题。

    • 原则二:你需要关注服务拆分的粒度,先粗略拆分再逐渐细化

    • 原则三: 拆分的过程,要尽量避免影响产品的日常功能迭代

    • 原则四: 服务接口的定义要具备可扩展性

    微服务化带来的问题和解决思路

    服务调用

    服务接口的调用不再是同一进程内的方法调用而是跨进程的网络调用,这会增加接口响应时间的增加。此时我们就要选择高效的服务调用框架,同时接口调用方需要知道服务部署在哪些机器的哪个端口上,这些信息需要存储在一个分布式一致性的存储中,于是就需要引入服务注册中心,注册中心管理的是服务完整的生命周期,包括对于服务存活状态的检测。

    依赖关系

    多个服务之间有着错综复杂的依赖关系。一个服务会依赖多个其它服务也会被多个服务所依赖,那么一旦被依赖的服务的性能出现问题产生大量的慢请求,就会导致依赖服务的工作线程池中的线程被占满,依赖的服务也会出现性能问题。接下来问题就会沿着依赖网逐步向上蔓延,直到整个系统出现故障为止。为了避免发生这种情况,我们需要引入服务治理体系针对出问题的服务采用熔断、降级、限流、超时控制的方法,使问题被限制在单一服务中,保护服务网络中的其它服务不受影响。

    问题追踪

    服务拆分到多个进程后,一条请求的调用链路上涉及多个服务,那么一旦这个请求的响应时间增长或者是出现错误,我们就很难知道是哪一个服务出现的问题。另外,整体系统一旦出现故障,很可能外在的表现是所有服务在同一时间都出现了问题,你在问题定位时很难确认哪一个服务是源头,这就需要引入分布式追踪工具,以及更细致的服务端监控报表。

    服务注册和发现的核心

    引入一个注册中心的中间件,来统一管理 服务端 和 客户端。采用的保证服务端正常运行的手段是——心跳机制。定时向注册中心发送心跳包表明自己运行正常。

    负载均衡:怎样提升系统的横向扩展能力

    • 代理类负载均衡服务
    • 客户端负载均衡服务

    如何检测节点是否故障

    • 通过注册中心异常检测
    • 通过负载均衡服务异常检测

    服务端监控要怎么做

    • 耗时、请求量和错误数是三种最通用的监控指标,不同的组件还有一些特殊的监控指标,你在搭建自己的监控系统的时候可以直接使用
    • Agent、埋点和日志是三种最常见的数据采集方式
    • 访问趋势报表用来展示服务的整体运行情况,性能报表用来分析资源或者依赖的服务是否出现问题,资源报表用来追查资源问题的根本原因

    服务端限流量

    限流方式有如下:

    • 固定窗口
    • 滑动窗口
    • 漏斗:一般用队列来实现,但是会造成请求有延迟并且也对处理突发流量不友好。
    • 令牌桶:通过往桶内定时放入一个令牌,请求过来时先要申请到令牌才能继续,否则请求失败,这个对于处理突发流量时比较友好,即平时可以攒,到突发流量时可以直接用起来,guava的ratelimiter就是令牌桶算法实现的,分布式令牌桶可以用redis来实现,可以一次申请多个而不是一个这样可以降低每次请求的开销

    参考

    资料参考

    展开全文
  • 并发系统的限流算法与实现

    千次阅读 多人点赞 2019-07-23 08:00:00
    开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。 缓存:缓存的目的是提升系统访问速度和增大系统处理容量。 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有...

    开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。

    • 缓存:缓存的目的是提升系统访问速度和增大系统处理容量。

    • 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。

    • 限流:限流的目的是通过对并发请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以进行拒绝服务、排队或等待、降级等处理。

    限流是限制系统的输入和输出流量,以达到保护系统的目的,而限流的实现主要是依靠限流算法,限流算法主要有4种:

    1. 固定时间窗口算法(计数器)

    2. 滑动时间窗口算法

    3. 令牌桶算法

    4. 漏桶算法

    1. 固定时间窗口算法

    又称计数器算法。固定时间窗口算法就是统计记录单位时间内进入系统或者某一接口的请求次数,在限定的次数内的请求则正常接收处理,超过次数的请求则拒绝掉或者改为异步处理等限流措施。

    时间窗口长度如果为1分钟,如图。

    640?wx_fmt=png

    此算法在单机还是分布式环境下实现都非常简单,使用redis的incr原子自增性即可轻松实现。

    单机伪代码如下。

    class CounterDemo {
        public       long timeStamp = getNowTime();
        public       int  reqCount  = 0;
        public final int  limit     = 100; // 时间窗口内最大请求数
        public final long interval  = 1000; // 时间窗口ms
    
        public boolean grant() {
            long now = getNowTime();
            if (now < timeStamp + interval) {
                // 在时间窗口内
                reqCount++;
                // 判断当前时间窗口内是否超过最大请求控制数
                return reqCount <= limit;
            } else {
                timeStamp = now;
                // 超时后重置
                reqCount = 1;
                return true;
            }
        }
    }

    算法特点

    1. 实现简单。

    2. 时间窗口固定,每个窗口开始时计数为零,这样后面的请求不会受到之前的影响,做到了前后请求隔离。

    3. 因为两个时间窗口之间没有任何联系,所以调用者可以在一个时间窗口的结束到下一个时间窗口的开始这个非常短的时间段内发起两倍于阈值的请求。所以固定时间窗口算法无法限制窗口间突发流量。

    2. 滑动时间窗口算法

    滑动时间窗口算法其实是固定时间窗口算法的优化,主要是为了解决固定时间窗口算法无法限制窗口间突发流量的缺点。
    上面的计数器的单位时间是1分钟,而在使用滑动时间窗口,可以把1分钟分成6格,每格时间长度是10s,每一格又各自管理一个计数器,单位时间用一个长度为60s的窗口描述。一个请求进入系统,对应的时间格子的计数器便会+1,而每过10s,这个窗口便会向右滑动一格。只要窗口包括的所有格子的计数器总和超过限流上限,便会执行限流措施。

    640?wx_fmt=png

    由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。

    算法特点

    1. 因为窗口顺延,所以可以抵御窗口间突发流量(对比固定时间窗口算法)。

    2. 假如限流10万次/小时,如果某个调用者在前10分钟调用了10万次那么他必须再等待1小时才能发起下一次正常请求。所以没有做到前后请求隔离。

    阿里开源的Sentinel,采用的是滑动窗口算法进行限流,可以阅读相关代码,加深对滑动时间窗口算法的理解。

    3. 漏桶算法(leaky bucket)

    漏桶算法其实很简单,可以粗略的认为就是注水漏水过程,往桶中以一定速率流出水,以任意速率流入水,当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。这个从桶底流出去的水就是系统正常处理的请求,从旁边流出去的水就是系统拒绝掉的请求。

    640?wx_fmt=jpeg

    单机伪代码如下。

    class LeakyDemo {
        public long timeStamp = getNowTime();
        public int capacity; // 桶的容量
        public int rate; // 水漏出的速度
        public int water; // 当前水量(当前累积请求数)
    
        public boolean grant() {
            long now = getNowTime();
            water = max(0, water - (now - timeStamp) * rate); // 先执行漏水,计算剩余水量
            timeStamp = now;
            if ((water + 1) < capacity) {
                // 尝试加水,并且水还未满
                water += 1;
                return true;
            } else {
                // 水满,拒绝加水
                return false;
            }
        }
    }

    算法特点

    1. 因为流出的速度是一定的,可以抵御突发流量,做到更加平滑的限流,而且不允许流量突发。

    4. 令牌桶算法(Token Bucket)

    令牌桶算法是比较常见的限流算法之一,Google开源项目Guava中的RateLimiter使用的就是令牌桶算法。流程如下:

    1. 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理。

    2. 根据限流大小,设置按照一定的速率往桶里添加令牌。

    3. 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝。

    4. 请求到达后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除。

    640?wx_fmt=png

    单机伪代码如下,分布式环境可以使用Redisson。

    class TokenBucketDemo {
        public long timeStamp = getNowTime();
        public int capacity; // 桶的容量
        public int rate; // 令牌放入速度
        public int tokens; // 当前令牌数量
    
        public boolean grant() {
            long now = getNowTime();
            // 先添加令牌
            tokens = min(capacity, tokens + (now - timeStamp) * rate);
            timeStamp = now;
            if (tokens < 1) {
                // 若桶中没有令牌,则拒绝
                return false;
            } else {
                // 还有令牌,领取令牌
                tokens -= 1;
                return true;
            }
        }
    }

    算法特点

    1. 可以抵御突发流量,因为桶内的令牌数不会超过给定的最大值

    2. 可以做到更加平滑的限流,因为令牌是匀速放入的。

    3. 令牌桶算法允许流量一定程度的突发。(相比漏桶算法)

    在时间点刷新的临界点上,只要剩余token足够,令牌桶算法会允许对应数量的请求通过,而后刷新时间因为token不足,流量也会被限制在外,这样就比较好的控制了瞬时流量。因此,令牌桶算法也被广泛使用。

     

    更多内容,欢迎关注微信公众号:全菜工程师小辉~

    640?wx_fmt=png

     

     

    展开全文
  • 如何设计一个高并发系统

    千次阅读 2019-01-10 13:42:02
    如何设计一个高并发系统? 如果你确实有真才实学,在互联网公司里,干过高并发系统,那你拿Offer,基本如探囊取物一样简单。 但你要真干过高并发系统,面试官绝对不会问这个问题,否则他就不太明智了。 因为真正干过...

    如何设计一个高并发系统?

    如果你确实有真才实学,在互联网公司里,干过高并发系统,那你拿Offer,基本如探囊取物一样简单。

    但你要真干过高并发系统,面试官绝对不会问这个问题,否则他就不太明智了。

    因为真正干过高并发的人一定知道,脱离了业务的系统架构,都是纸上谈兵。

    真正在复杂业务场景、而且还高并发的时候,这个系统架构一定很难搞。

    要理解高并发,就得从高并发的根源出发——为什么会有高并发?为什么高并发就很牛X?

    因为刚开始,系统都是连接数据库的,但是数据库支撑到每秒并发两三千的时候,基本就快完了。

    数据库如果瞬间承载每秒5000、8000、甚至上万的并发,一定会宕机,因为比如MySQL就压根儿扛不住这么高的并发量。

    所以为什么高并发牛X?

    因为现在网民越来越多,很多App、网站、系统承载的都是高并发请求,高峰期每秒并发量几千都很正常。就像每年的双十一,一年比一年的峰值高,每秒并发几十万,都是洒洒水。

    那么,我们可以从以下几个方面,来进行考虑:

    1、系统拆分。将一个系统拆分为多个子系统,用Dubbo来搞。然后每个系统连一个数据库,这样本来就一个库,现在多个数据库,就可以抗高并发了。

    2、缓存。必须得用缓存。大部分的高并发场景,都是读多写少。你完全可以在数据库和缓存里都写一份,然后读的时候,大量走缓存就行了。

    3、MQ。必须得用MQ。

    可能你还是会出现高并发写的场景,比如说一个业务操作里,要频繁搞数据库几十次,增删改增删改,疯了。

    那你咋办?用MQ吧,大量写请求灌入MQ里,排队慢慢玩儿,后边系统消费后慢慢写,控制在MySQL承载范围之内。

    4、分库分表。可能到了最后,数据库层面还是免不了抗高并发的要求,好吧,那么就将一个数据库,拆分为多个库,多个库来抗更高的并发。

    然后将一个表,拆分为多个表,每个表的数据量,保持少一点,提高SQL跑的性能。

    5、读写分离。多数时候,数据库可能也是读多写少,没必要所有请求,都集中在一个库上。

    可以搞个主从架构,主库写入,从库读取,搞一个读写分离。读流量太多的时候,还可以加更多的从库。

    6、Elasticsearch,可以考虑用ES。ES是分布式的,可以随便扩容,分布式天然就可以支撑高并发,因为动不动就可以扩容加机器,来抗更高的并发。

    如何解决单点故障?

    一个网站,从基础的硬件层、到操作系统层、到数据库层、到应用程序层、再到网络层,都有可能产生单点故障。

    如果要有效地消除单点故障,最重要的一点,是设计的时候,要尽量避免引入单点,随着架构的变化,定期审查系统潜在的单点,也是有必要的。

    大体可以从以下几个方面,来消除单点故障:

    增加硬盘,做镜像。让出错的概率降低。

    网卡与网线的单点问题。系统里面最容易物理损坏的就是网线,网卡绑定(NIC bonding)是一个很简单、很通用的办法,建议你配置多个网卡。

    SSH服务器和Telnet服务器共存。毕竟SSH和Telnet,都不是百分之百靠谱的事;

    IDC机房的单点。由于中国特色的“南北互通”,所以选择IDC机房的时候,一定要有冗余。

    靠谱的DNS解析。

    原文:https://blog.csdn.net/csdnnews/article/details/86065474

    展开全文
  • 如何设计一个高并发系统架构

    千次阅读 2019-05-27 10:37:58
    1,一般一个高并发系统的架构组成如下图所示: 2,面试题 如何设计一个高并发系统? 3、面试官心里分析 说实话,如果面试官问你这个题目,那么你必须要使出全身吃奶劲了。为啥?因为你没看到现在很多公司招聘的jd里...

    1,一般一个高并发系统的架构组成如下图所示:
    在这里插入图片描述
    2,面试题

    如何设计一个高并发系统?

    3、面试官心里分析

    说实话,如果面试官问你这个题目,那么你必须要使出全身吃奶劲了。为啥?因为你没看到现在很多公司招聘的jd里都是说啥,有高并发就经验者优先。

    所以如果你确实有真才实学,在互联网公司里干过高并发系统,那你确实拿offer基本如探囊取物,没啥问题。但是如果你要是真是干过高并发系统,面试官绝对绝对不会问这个问题,否则他就是蠢。

    假设你在某知名电商公司干过高并发系统,用户上亿,一天流量几十亿,高峰期并发量上万,甚至是十万。那么人家一定会仔细盘问你的系统架构,你们系统啥架构?怎么部署的?部署了多少台机器?缓存咋用的?MQ咋用的?数据库咋用的?就是深挖你到底是如何抗下高并发的。

    因为真正干过高并发的人一定知道,脱离了业务的系统架构都是在纸上谈兵,真正在复杂业务场景而且还高并发的时候,那系统架构一定不是那么简单的,用个redis,用mq就能搞定?当然不是,真实的系统架构搭配上业务之后,会比这种简单的所谓“高并发架构”要复杂很多倍。

    如果有面试官问你个问题说,如何设计一个高并发系统?那么不好意思,一定是因为你实际上没干过高并发系统。面试官看你简历就没啥出彩的,感觉就不咋地,所以就会问问你,如何设计一个高并发系统?其实说白了本质就是看看你有没有自己研究过,有没有一定的知识积累。

    最好的当然是招聘个真正干过高并发的哥儿们咯,但是这种哥儿们人数稀缺,不好招。所以可能次一点的就是招一个自己研究过的哥儿们,总比招一个傻也不会的哥儿们好吧!

    所以这个时候你必须得做一把个人秀了,秀出你所有关于高并发的知识!

    3、面试题剖析

    其实所谓的高并发,如果你要理解这个问题呢,其实就得从高并发的根源出发,为啥会有高并发?为啥高并发就很牛逼?

    我说的浅显一点,很简单,就是因为刚开始系统都是连接数据库的,但是要知道数据库支撑到每秒并发两三千的时候,基本就快完了。所以才有说,很多公司,刚开始干的时候,技术比较low,结果业务发展太快,有的时候系统扛不住压力就挂了。

    当然会挂了,凭什么不挂?你数据库如果瞬间承载每秒5000,8000,甚至上万的并发,一定会宕机,因为比如mysql就压根儿扛不住这么高的并发量。

    所以为啥高并发牛逼?就是因为现在用互联网的人越来越多,很多app、网站、系统承载的都是高并发请求,可能高峰期每秒并发量几千,很正常的。如果是什么双十一了之类的,每秒并发几万几十万都有可能。

    那么如此之高的并发量,加上原本就如此之复杂的业务,咋玩儿?真正厉害的,一定是在复杂业务系统里玩儿过高并发架构的人,但是你没有,那么我给你说一下你该怎么回答这个问题:

    (1)系统拆分,将一个系统拆分为多个子系统,用dubbo来搞。然后每个系统连一个数据库,这样本来就一个库,现在多个数据库,不也可以抗高并发么。

    (2)缓存,必须得用缓存。大部分的高并发场景,都是读多写少,那你完全可以在数据库和缓存里都写一份,然后读的时候大量走缓存不就得了。毕竟人家redis轻轻松松单机几万的并发啊。没问题的。所以你可以考虑考虑你的项目里,那些承载主要请求的读场景,怎么用缓存来抗高并发。

    (3)MQ,必须得用MQ。可能你还是会出现高并发写的场景,比如说一个业务操作里要频繁搞数据库几十次,增删改增删改,疯了。那高并发绝对搞挂你的系统,你要是用redis来承载写那肯定不行,人家是缓存,数据随时就被LRU了,数据格式还无比简单,没有事务支持。所以该用mysql还得用mysql啊。那你咋办?用MQ吧,大量的写请求灌入MQ里,排队慢慢玩儿,后边系统消费后慢慢写,控制在mysql承载范围之内。所以你得考虑考虑你的项目里,那些承载复杂写业务逻辑的场景里,如何用MQ来异步写,提升并发性。MQ单机抗几万并发也是ok的,这个之前还特意说过。

    (4)分库分表,可能到了最后数据库层面还是免不了抗高并发的要求,好吧,那么就将一个数据库拆分为多个库,多个库来抗更高的并发;然后将一个表拆分为多个表,每个表的数据量保持少一点,提高sql跑的性能。

    (5)读写分离,这个就是说大部分时候数据库可能也是读多写少,没必要所有请求都集中在一个库上吧,可以搞个主从架构,主库写入,从库读取,搞一个读写分离。读流量太多的时候,还可以加更多的从库。

    (6)Elasticsearch,可以考虑用es。es是分布式的,可以随便扩容,分布式天然就可以支撑高并发,因为动不动就可以扩容加机器来抗更高的并发。那么一些比较简单的查询、统计类的操作,可以考虑用es来承载,还有一些全文搜索类的操作,也可以考虑用es来承载。

    上面的6点,基本就是高并发系统肯定要干的一些事儿,大家可以仔细结合之前讲过的知识考虑一下,到时候你可以系统的把这块阐述一下,然后每个部分要注意哪些问题,之前都讲过了,你都可以阐述阐述,表明你对这块是有点积累的。

    说句实话,毕竟真正你厉害的一点,不是在于弄明白一些技术,或者大概知道一个高并发系统应该长什么样?其实实际上在真正的复杂的业务系统里,做高并发要远远比我这个图复杂几十倍到上百倍。你需要考虑,哪些需要分库分表,哪些不需要分库分表,单库单表跟分库分表如何join,哪些数据要放到缓存里去啊,放哪些数据再可以抗掉高并发的请求,你需要完成对一个复杂业务系统的分析之后,然后逐步逐步的加入高并发的系统架构的改造,这个过程是务必复杂的,一旦做过一次,一旦做好了,你在这个市场上就会非常的吃香。

    其实大部分公司,真正看重的,不是说你掌握高并发相关的一些基本的架构知识,架构中的一些技术,RocketMQ、Kafka、Redis、Elasticsearch,高并发这一块,次一等的人才。对一个有几十万行代码的复杂的分布式系统,一步一步架构、设计以及实践过高并发架构的人,这个经验是难能可贵的。

    我这边其实平时我会发布一些免费的课程,每隔一段时间定期发布一点,主要是尽可能给大家讲一些免费的课程,保证质量, 让大家学到一些东西。

    我主要还是专注在自己的架构师体系的课程上面,是一年多的时间,非常长,内容极其庞大,我从一开始就带着你从0开始,动手构建一个10万行以上代码量的这么个庞大的系统,针对这种复杂系统的业务场景,里面隐含的各种技术问题和坑,我会通过1年多的时间,一步一步的讲解各种技术和架构,解决真实的大型的系统中的各种问题。

    展开全文
  • 如何设计一个高并发系统,现在这个是每个架构师都需要考虑的问题。当然每个人面对的业务场景都不一样,这里我们纯粹从技术角度探讨。我总结了下,要点如下: 负载均衡、缓存优先 服务拆分(系统拆分)、冗余扩容 ...
  • 并发系统之降级

    千次阅读 2017-06-20 14:37:15
    在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。之前已经有一些文章介绍过缓存和限流了。本文将详细聊聊降级。当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能...
  • 如何设计一个高并发系统

    千次阅读 2019-08-01 09:02:14
    如何设计一个高并发系统
  • Java高并发系统的限流策略

    万次阅读 2018-05-12 23:03:33
    在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。缓存缓存比较好理解,在大型高并发系统中,如果没有缓存数据库将分分钟被爆,系统也会瞬间瘫痪。使用缓存不单单能够提升系统访问速度...
  • 并发系统设计40问 - 学习/实践

    千次阅读 2019-09-29 16:14:27
    开篇词 | 为什么你要学习高并发系统设计? 基础篇 (6讲) 【01 | 高并发系统:它的通用设计方法是什么?】 见TBD 【02 | 架构分层:我们为什么一定要这么做?】 【03 | 系统设计...
  • 谈谈高并发系统的限流

    千次阅读 2018-04-11 18:39:01
    开涛大神在博客中说过:在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。本文结合作者的一些经验介绍限流的相关概念、算法和常规的实现方式。缓存缓存比较好理解,在大型高并发系统中,如果没有缓存...
  • 并发系统限流设计

    千次阅读 2018-02-08 11:21:16
    并发系统时有三把利器用来保护系统:缓存、降级和限流,缓存的目的是提升系统访问速度和增大系统能处理的容量,降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰或者问题解决后再打开,而有些...
  • 面试官问你如何设计一个高并发系统,其实多半是因为知道你没干过高并发。看你简历也没啥特别的,所以就问问你,如何设计。就是想考察你是否有技术储备。 最好是招聘个真正有高并发经验的,但众所周知国内缺乏这种中...
  • 并发系统的瓶颈与优化总结

    千次阅读 2017-10-08 23:32:32
    一、高并发系统的瓶颈 1.MySQL服务器与后端服务器之间的网络延迟 2.后端采用事务管理,MYSQL行级锁造成数据阻塞,使得并发量大打折扣。 二、高并发系统的优化方案 1.前端优化:对于可以造成高点击量的按钮采取...
  • 浅谈高并发系统性能调优

    千次阅读 2018-08-30 18:00:00
    女主宣言今天带来的是一个篇长文,主要讲解高并发系统架构指标及调优测试经验,希望能对您的研究有所帮助。本文最先发布于 OpsDev,转载已获取作者授权。PS:丰富的一线技术...
  • 并发系统中的尾延迟

    千次阅读 2018-05-01 10:29:43
    开发和运维高并发系统的工程师可能都有过类似经验,明明系统已经调优完毕,该异步的异步,该减少互斥的地方引入无锁,该减少IO的地方更换引擎或者硬件,该调节内核的调节相应参数,然而,如果在系统中引入实时监控,...
  • 高可用高并发系统设计原则 这份图,互联网架构下的【高可用高并发】系统设计原则,在我团队成员里,人手打印了一份放在桌面上,便于时刻回顾和学习总结,希望对你有用 推荐阅读 亿级流量-高并发高可用架构...
  • 并发系统之限流特技

    万次阅读 多人点赞 2016-06-12 21:49:03
    在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹;而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,...
  • 41、如何设计一个高并发系统

    千次阅读 2019-01-11 09:14:47
    如何设计一个高并发系统? 2、面试官心里分析 说实话,如果面试官问你这个题目,那么你必须要使出全身吃奶劲了。为啥?因为你没看到现在很多公司招聘的jd里都是说啥,有高并发就经验者优先。 所以如果你确实有...
  • 如果你确实有真才实学,在互联网公司里,干过高并发系统,那你拿Offer,基本如探囊取物一样简单。 但你要真干过高并发系统,面试官绝对不会问这个问题,否则他就不太明智了。 因为真正干过高并发的人一定知道,...
  • 项目-高并发系统三大利器

    千次阅读 2017-04-27 16:27:02
    保护高并发系统的三大利器:缓存、降级、限流。 缓存:提升系统的访问速度,增大系统处理容量;降级:当服务出现问题或影响到核心流程时,需要暂时屏蔽掉,待高峰过后或问题解决后再打开;限流:当不可降级场景...
  • 缓存、降级和限流 高并发系统
  • 针对高并发系统的解决思路与方案

    千次阅读 2018-08-23 21:41:56
    开涛大神在博客中说过:在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。 1.扩容 根据业务系统的类型,考虑不同的针对在数据库方面的扩容: 2.缓存(特别重要) 缓存设置的地方 手段 主要...
  • 并发系统的设计及秒杀实践

    万次阅读 2016-11-23 17:33:02
    一个大型网站应用一般都是从... 这些技术是高并发系统所必须的,但是今天先不细说,而先谈谈在这些架构既定的情况下,一些高并发业务/接口实现时应该注意的原则,以及通过工作中一个6万QPS的秒杀活动,来介绍一下秒杀业
  • 如何保障高并发系统的稳定性与高可用 文章来源:企鹅号 - 品质出行技术 要论如何搞垮一家互联网公司,速度最快的不是产品经理的胡乱决策,运营的无休止的烧钱,客服人员对客户的冷漠,一定是系统核心功能持续不可用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 87,603
精华内容 35,041
关键字:

并发系统