高并发解决的核心问题是在同一时间上有大量的请求过来,然后我们的系统要怎么抗住这些请求带来的压力。本文从基础设施层、服务端架构层、服务应用层分别做了一个简单的梳理,在每一层通过什么的方式去抗并发,给大家提供一个思路。
高并发解决的核心问题是在同一时间上有大量的请求过来,然后我们的系统要怎么抗住这些请求带来的压力。比如在线直播服务,同时有上百万甚至上千万人观看。比如秒杀品,同时有大量用户涌入。
高并发是从业务角度去描述系统的能力,实现高并发的手段可以采用分布式,也可以采用缓存等,当然也包括多线程、协程,但远远不仅如此;高并发的基本表现为单位时间内系统能够同时处理的请求数,高并发的核心是对资源的有效压榨,有限的资源应对大量的请求。
现代互联网服务,基本上都要考虑高并发问题,因为一般的产品,用户的请求量都很大。
高并发架构设计,需要从三大层来建设和分析
基础设施层一般包含了服务器、IDC、部署方式等等。目前而言,我们一般都用容器部署的方式,而容器的底层能力基本也都是建立在 k8s 容器层之上的,服务本身的部署管理已经有成熟的设施帮我们实现了。具体到部署方式,包括但不限于:
系统的可观测性主要包含三个部分: logging、tracing、metrics。 这个一般都要引入可观测系统,这样才能帮助我们在异常的时候能够快速定位问题。属于必备设施,一般而言,公司应该都有专门的团队去做这个事情。
服务端架构层是我们重点要关注的,这个也是考量个人架构能力的最关键部分。
应对高并发系统,不管是应用层面还是数据层面,单机都不可能搞定,因此都需要搭建集群架构,然后通过负载均衡来对外提供服务。同时集群架构还能保证系统的可用性,当某台服务或者机器异常,负载均衡会自动剔除,不会影响对外服务。
数据库设计:读写分离+分库分表+冷热分离
应对高并发,数据的存储,首先就要做好预估,先进行分库分表 和 读写分离,最后可以根据情况来看是否冷热分离:
不过,既然是高并发系统,不能应用层直接读写 DB 的,一定有一个缓存在上面,如果直接读写 DB 能够搞定,其实不能叫高并发了,只能说是并发有点高。在非互联网系统里面还是可以的。
缓存的最大作用是可以提升系统性能,保护后端存储不被大流量打垮,增加系统的伸缩性。缓存的设计,需要分多个思路并行
针对流量突峰,仅仅有缓存来抗量可能还不够,还需要使用消息队列来削峰。使用消息队列后,可以将同步处理的请求改为 通过消费 MQ 消息来异步消费,这样可以大大减少系统处理的压力,增加系统的并发量。常用的消息队列比如 kafka。
超时、熔断、降级、限流等都是常规策略,可以在另外服务治理章节去细看。
资源隔离有各种类型,物理层面的服务器资源、中间件资源,代码层面的线程池、连接池,这些都可以做隔离。
一般我们最常见的就是应用部署层面的,比如 SET 化部署。一个服务对外的使用方可能有 A 业务、B 业务,那么如何保证 AB 业务不会相互影响,那么就是 SET 化部署。 SET 化部署也可以防止非关键业务来影响关键核心业务。一个隔离的维度可以是按业务场景区分,分为关键集群、次关键集群和非关键集群三类,这样能避免关键和非关键业务互相影响。
SET 化部署就是把业务系统分为多个可扩展的逻辑分区,每个 SET 化的逻辑分区都可以独立部署并提供服务,SET 也可以理解为 ”逻辑机房“ ,主要目的就是为了进行独立部署并且做到业务上的逻辑隔离。
关于 SET 的具体例子:微信红包用户发一个红包时,微信红包系统生成一个 ID 作为这个红包的唯一标识。接下来这个红包的所有发红包、抢红包、拆红包、查询红包详情等操作,都根据这个 ID 关联。红包系统根据这个红包 ID,按一定的规则(如按 ID 尾号取模等),垂直上下切分。切分后,一个垂直链条上的逻辑 Server 服务器、DB 统称为一个 SET。各个 SET 之间相互独立,互相解耦。并且同一个红包 ID 的所有请求,包括发红包、抢红包、拆红包、查详情详情等,垂直 stick 到同一个 SET 内处理,高度内聚。通过这样的方式,系统将所有红包请求这个巨大的洪流分散为多股小流,互不影响,分而治之,
并发问题一直是服务端编程中的重点和难点问题,为了优化系统的并发量,单机解决高并发问题从最初的 Fork 进程开始,到进程池/线程池,再到 Epoll 事件驱动(Nginx),再到协程(如 Goroutine)。
对于 Go 语言,尽可能的多使用协程去提高并发能力。
消息队列也是一种异步化操作,但是除了依赖外部的中间件如消息队列,在应用内我们也可以通过线程池、协程的方式做异步化,能异步的尽量异步处理,这样可以提高并发。
系统的预热一般有 JVM 预热、缓存预热、DB 预热等,通过预热的方式让系统先“热”起来,为高并发流量的到来做好准备。 预热实际应用的场景有很多,比如在电商的大促到来前,我们可以把一些热点的商品提前加载到缓存中,防止大流量冲击 DB。
还有一种预热的思路是利用业务的特性做一些预加载,比如 feeds 流刷新的时候,提前加载 1-2 页数据,这样用户往下刷新的时候,就感觉不到卡顿。
作者:allendbwu
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:
在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g
我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails
我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow
我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的