必备面试题之 - 高并发

分类: 互联网 > 面试题

1、高性能架构

较短的响应时间、较大的并发处理能力、较高的吞吐率和稳定的性能参数。

    1.1 请求分发:如果请求时无状态,那么比较容易做负载均衡

        1.1.1 请求分发的实现方式:

            1)nginx proxy

            2)HAproxy

            3)LVS

            4)硬件负载均衡器

            5)dns

        1.1.2 选型分析:

            1)网站建设初期,可以选用Nginx/HAproxy作为反向代理负载均衡(或者流量不大都可以不选用负载均衡),因为其配置简单,性能也能满足一般的业务场景。

            2)如果考虑到负载均衡器是有单点问题,可以采用Nginx/HAproxy+Keepalived来避免。

            3)网站并发达到一定程度之后,为了提高稳定性和转发效率,可以使用LVS、毕竟LVS比Nginx/HAproxy要更稳定, 转发效率也更高。

            4)大型站点可以基于DNS域名解析

    1.2 响应前置:响应前置通过减少一些调用流程,实现数据更加实时返回

        1.2.1 前置到接入层

            目前比较推崇接入层(如nginx)直接返回数据,无需调用后端程序(如go,php,java等程序)

            openResty介绍

                1)openResty是一个基于Nginx与Lua的高性能平台,内部集成了大量精良的Lua库、第三方模块以及大多数的依赖项。

                2)openResty通过汇聚各种设计精良的Ngnix模块,从而将Ngnix有效变成一个强大的通过web应用平台,使用Lua脚本语言调用Ngnix支持的各种C以及Lua模块

                3)openResty的目标是让你的web服务直接跑在Nginx服务内部、充分利用Nginx的非阻塞I/O模型

            1.2.2 将上次访问的数据生成一个前置缓存,从而第二次无需深入访问

        1.3 拆分:集中化系统进化

            1.3.1 服务拆分:基于RPC的微服务框架,拆分多个服务,例如挂号服务,订单服务,支付服务等等

            1.3.2 插件拆分:与服务拆分不同,插件拆分表现为前后端一整套嵌入,而服务拆分是后端的拆分

            1.3.3 技术组件拆分:js图片处理组件拆分,api加密组件拆分

            1.3.4 数据库拆分:

                分库分表

                1)哈希分表:插入压力也分散,解决了集中插入的问题,但存在拓展问题

                2)分段分表:插入压力没分散,解决了数据库拓展问题

                分布式事务

                2阶段:mysql自带的xa事务

                3阶段:增加一个健康检测间断

                TCC:基于业务层面接口实现

                MQ最终一致性:消息队列 rabbit的消息可靠性传递

            1.3.5 nosql以及搜索引擎拆分

                1)redis集群哈希分槽:Redis集群的键空间被分割为16384 hash个槽(slot),集群最大节点数量也是16384个

                2)mongodb集群分片:多个分片例如shard1、shard2、shard3 位于三台不同服务器

                3)elasticsearch分片

            1.3.6 消息队列拆分

        1.4 数据结构优化:目的是优化数据的空间利用率和查询效率,比如mysql索引优化

        1.5 消息队列:消息队列可以实现服务解耦,异步处理,流量削峰/缓冲等:rabbitMQ,kafka,redis

        1.6 数据异构与聚合

            1.6.1 数据异构

                1)概念:一种数据结构可能无法适用所有业务,我们基于当前数据内容又塑造其他数据结构,这样就多份数据荣誉,多份数据的结构是不一样的,目的是使用更多的业务场景

                2)数据异构:用空间换时间

            1.6.2 数据聚合

                减少多个表的数据查询,提前存json数据,返回给前端就是这条json数据,而这条数据是支持随时进行局部修改的(mongo)

        1.7 缓存

            1.7.1 浏览器缓存:浏览器缓存是浏览器端保存数据用于快速读取或避免重复资源请求的优化机制

                1)http缓存:基于http协议的浏览器文件级缓存机制

                2)cookie数据(数KB/站点)

                3)localstorage(5MB/站点)

                4)sessionstorage:sessionStorage和localStorage类似,但浏览器关闭会全部删除

                5)WebSQL:数据库,只有新浏览器才支持

                6)indexDB:是一个为了能够在客户端存储可观数据的结构化数据,并且在这些数据上使用索引进行高性能检索的API

                7)application cache:是将大部分图片资源、js、css等静态资源放在mainfest文件配置中

                8)cacheStorage

            1.7.2 CDN缓存:将静态内容分布并缓存到对应的网络节点,减少直接访问到源服务器

            1.7.3 反向代理缓存:接入层缓存(nginx的share_dict等),通过存入缓存,减少对后端服务器的调用次数

            1.7.4 nosql缓存

            1.7.5 文件缓存:以文件的形式保存的缓存

        1.8 程序优化

            1.8.1 io模型:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、异步IO

                1)阻塞IO:在内核将数据准备好之前,系统调用会一直等待。所有的套接字默认都是阻塞方式。【在等待的过程中,被阻塞的执行流什么都干不了,对cpu的利用率较低,但实时性比较好】

                2)非阻塞IO:如果内核还没将数据准备好,系统调用仍然会直接返回,并且返回EWOULDBLOCK错误码。非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询【程序对cpu的利用率比阻塞IO高,但不够实时】

                3)多路复用IO:也称IO多路转接,核心在于多路转接能够同时等待多个文件描述符的就绪状态

                4)信号驱动IO:内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作

                5)异步IO:由内核在数据拷贝完成时,通知应用程序,IO等待和数据拷贝操作都是在系统内核完成,完成之后通过信号来通知程序

            1.8.2 并发处理:多个任务并行

            1.8.3 连接池:比如redis连接池、mysql连接池

            1.8.4 代码调优:框架架构优化,sql语句,对象,循环,执行逻辑等等的优化

        1.9 集群:redis、mongoDB、ES、solr、kafka、rabbitMQ都支持集群

        1.10 前端优化:

            1.10.1 浏览器优化、反向代理缓存

            1.10.2 压缩技术:包括js、css、图片的压缩,轻量级的内容更容易到达用户、而且节约宽带,对于高访问高并发的站点尤其重要

            1.10.3 nginx优化

                1)sendfile on sendfile: 设置为on表示启动高效传输文件的模式。

                2)gzip压缩示例

            1.10.4 前端异步:包括异步加载js文件,以及异步调用接口

                1)异步加载js文件: 异步加载js文件,可以有效防止js阻塞整个页面的加载进度,一般通过async="async"标签实现

                2)异步加载html文件

                3)ajax同步异步

        1.11 硬件优化:硬件资源、网络带宽

2、高可用架构

    2.1 高可用概念:可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间返回结果

    2.2 集群主从

    2.3 降级、限流算法

        2.3.1 降级:为了保证核心功能的可用性,而选择性的降低一些次要功能的可用性,实时性,或者把这些功能从不实时的缓存中获取、或者直接关闭该功能【1、配置中心手动降级 2、基于nginx的漏桶自动降级】

        2.3.2 限流算法:

            1. 令牌桶算法:以固定的速率生成token,放入到令牌桶中,获取令牌才可以访问

            2. 漏桶算法:按照常量固定速率流出请求

            令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是足够,当令牌数减为零时,则拒绝新的请求。 漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数积到漏桶容量时,则新流入的请求被拒绝。 令牌桶限制的是平均流入速率(允许突发请求,只要有令牌就可以处理,又付一次拿3个令牌,或4个令牌),并允许一定程度的突发流量。 漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是1的率流 出,而不能一次是1,下次又是2),从而平滑突发流入速率。 令牌桶允许一定程度的突发,而漏桶主要目的是平滑流入速率。

    2.4 负载均衡故障切换

        1. MHA切换:

1. 配置文件检查阶段,这个阶段会检查整个集群配置文件配置
2. 宕机的 master 处理,这个阶段包括虚拟 ip 摘除操作,主机关机操作(由于没有定义power_manager脚
本,不会关机)
3. 复制 dead maste 和最新 slave 相差的 relay log,并保存到 MHA Manger 具体的目录下
4. 识别含有最新更新的 slave
5. 应用从 master 保存的二进制日志事件(binlog events)(这点信息对于将故障master修复后加入集群很重
要)
6. 提升一个 slave 为新的 master 进行复制
7. 使其他的 slave 连接新的 master 进行复制

        2. Nginx故障切换

    2.5 健康检测

        2.5.1 consul

        2.5.2 nginx:nginx_upstream_check_module模块主动检查健康状态

    2.6 多分组,多机房:抗风险

    2.7 隔离:爬虫隔离、热点隔离、查询隔离、数据隔离

    2.8 cap理论:

        2.8.1 系统处理的状态:

            1)强一致性:这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大。

            2)弱一致性:这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不久承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。

            3)最终一致性:最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里 之所以将最终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型。

        2.8.2 cap理论详细:

            1)一致性C:在分布式环境下,一致性是指数据在多个副本之间能否保持一致的特性。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。

            2)可用性A:可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。这里的重点是"有限时间内"和"返回结果"。

            3)分区容错性P:分区容错性约束了一个分布式系统具有如下特性:分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。

3、可伸缩架构
    伸缩性是指在不改变原有架构设计的基础上,通过添加/减少硬件(服务器)的方式,提高/降低系统的处理能力。
应用层:对应用进行垂直或水平切分。然后针对单一功能进行负载均衡(DNS、HTTP[反向代理]、IP、链路层)。
服务层:与应用层类似;
数据层:分库、分表、NoSQL等;常用算法Hash,一致性Hash。
搜索引擎:es分片
消息队列:kafka partion分区机制
前端资源:多个负载机器
接入层:多个nginx服务器
分布式文件系统 
    3.1 扩容与缩容场景:适合访问量或计算量、容量不断变化的场景, 当量上去的时候,需要通过扩容来缓解压力, 扩容最简单的场景
    3.2 elasticsearch:
        3.2.1 调整es副本数
        3.2.2 调整es分片数
    3.3 mysql伸缩
        3.3.1 mysql主库伸缩:通过分库分表实现扩容,一般情况下,不会考虑对mysql进行缩容。
        3.3.2 mysql从库伸缩:通过增加读库数量实现扩容, 减少读库数量实现缩容
来源:原创 发布时间:2022-06-20 09:49:02