面试整理——分布式

分布式

一. 综合

问:集中式和分布式都有哪些特点?

集中式系统中数据以及所有业务单元都集中在中心节点,部署结构简单,无需考虑多个节点的部署。

分布式系统:

  • 分布性:机器在空间上随意分布。
  • 对等性:机器间没有主从之分,每个节点都是对等的。分布式系统常用副本这一概念来冗余数据和服务,比如在不同节点持久化同一份数据,避免数据完全丢失;或多个节点提供相同服务等。
  • 并发性:分布式系统中多个节点很可能会并发的操作一些共享资源。
  • 缺乏全局时钟:分布式系统中各个进程分布在任意空间,通过消息相互通信,所以相比单机有本机时间,分布式系统天然具有时间差。
  • 故障总是会发生:设计阶段考虑到的异常情况总是会在实际运行中发生。

问:并发环境下Scale-up(纵向扩展)和 Scale-out(横向扩展)的选择

  • Scale-up(纵向扩展):提高单核处理能力,购买更好的服务器硬件来提高并发能力
    • 优点:方案简单,成本低,适合项目初期,以及并发场景不频繁的系统。
    • 缺点:单机有极限,无法应对高并发场景。
  • Scale-out(横向扩展):扩展多核心整体处理能力,当需求场景以及预计的未来发展后,系统并发超过单机极限时建议采用。
    • 优点:理论上可以无限扩展,足以应对复杂需求的高并发问题。
    • 缺点:为系统引入了复杂性问题,如单点故障问题、单点性能瓶颈问题、一致性问题等。

问:高并发场景下接口优化思路?

三个方向:

  1. scale-out 横向扩展:通过分布式部署将流量分流,让服务器集群来共同承担并发流量。
  2. 缓存:以空间换取时间,先把流量排队,再根据策略处理。缓存的作用是提高系统的访问性能,把热数据抽取到相比磁盘读取速度更快的区域。
  3. 异步:在特定的场景下,未处理成功的请求提前返回,等待数据处理成功后再通过回调或事件通知等方式反馈给请求方。相比同步有更短的响应时间,并且能同时吞下多得多的请求,虽然并没有直接提高单个请求的处理速度。

答:

  1. 添加负载均衡层,将请求均匀分配到系统层(横向扩展)。
  2. 系统层采用集群化部署多台机器,抗住初步的并发压力(横向扩展)。
  3. 数据库分库分表 + 读写分离或微服务(横向扩展),数据库本身不是用来承载高并发请求的。
  4. 缓存集群引入(缓存)。
  5. 消息中间件技术,如MQ集群,做写请求异步化处理,实现削峰填谷的效果(异步)。

问:系统分层设计的优缺点?

优点:

  1. 各层各司其职,独立职责,并相互协同。
  2. 下层对上层隔离细节,简化系统,做上层的人无需了解下层实现。
  3. 分层解耦后,可以提高复用率,通用的部分抽层出来独立。
  4. 分层解耦后,提高系统的可扩展性,对单层进行扩展相比整个系统复杂度要低很多。

缺点:

  1. 增加代码复杂度,比如简单的请求本可以直接访问数据,要多几层调用,仅做数据传递。
  2. 增加调试难度。
  3. 增加部分性能损耗,层之间独立部署时,必要要在传输上增加损耗。

问:系统性能优化的大致思路?

  1. 问题导向,不过度优化:不过早的优化提升系统复杂度,占用开发资源,而是针对系统已存在的问题,或者即将面对的问题。
  2. 梳理优先级:紧抓主要性能瓶颈点,当问题有多个时,按重要性来排序处理,用20%的精力处理80%的性能问题。
  3. 记录数据:优化前后的响应时间、吞吐量、资源占用等数据记录清楚,了解优化提升了多少性能。
    • 性能的度量指标:如接口响应时间,有平均值、最大值、分位值。分位值适合统计一段时间内响应的统计值,排除了偶发的慢请求的影响,如1分钟内有100个请求,取响应时间正序第90个。
    • 如某个接口响应时间在10ms,吞吐量为100次/s。经过下述优化后,响应时间缩短为1ms,吞吐量则提升为400次/s。
      • 提高并发处理量:我们分析后发现该接口为单点处理,可以通过提高适当数量的并发核心数来优化;
      • 提高单次处理速度:首先分析场景是CPU密集还是IO密集,前者通过优化算法、减少运算次数等来优化,后者是指大部分操作都在等待IO完成(磁盘和网络都算),系统中常见的也是这种,平时通过采集/性能监控工具就可以发现。根据IO瓶颈场景来具体问题具体分析,比如数据库、缓存、网络。
  4. 持续扫描,持续优化:通过插件、工具等保持一定频率的性能扫描,对于开发过程中新产生的性能问题持续跟踪优化。

问:什么是高可用,如何让系统做到高可用?以及如何让系统容易扩展

高可用性(High Availability,HA)指的是系统具备较高的无故障运行的能力

  1. 如何度量可用性?

    两个时间:

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

    一个公式:

    • Availability = MTBF / (MTBF + MTTR)
    • 可用性要求越高,故障时间在总时间的占比要越低,比如要求一年可用性为99%,那么计算下来这一年故障时间要低于3.65天,每天要平均少于15分钟。

    当可用性要求提高到一定程度,响应时间的要求会缩短到分钟甚至秒,这种情况下单靠人力恢复是无法保障的,需要系统的容灾和自动恢复能力。一般核心系统要求可用性为99.99,非核心系统为99.9。

    提高可用性有时是以牺牲用户体验或系统性能来保障的,所以如何取舍很关键

  2. 系统设计:开发角度是通过冗余和取舍来保障,冗余节点,取舍服务。

    • 故障转移(failover):
      1. 对等节点:每个节点都相当于另一个节点的镜像,当一个节点宕机,只要根据访问策略(比如随机)转发到另一个节点即可。
      2. 不对等节点:比如主备节点,备用节点可能是热备也可能是冷备,那么我们要有检测主备服务器是否故障的逻辑(比如心跳),以及故障后如何在主备间切换的流程(比如多个备节点选主的过程要做一致性,需要分布式一致性算法,如Paxos,Raft)。
    • 调用超时控制:失败是瞬时的,但延迟是系统更危险的场景。失败可以重试,但延迟会导致阻塞,资源一直被占用。所以系统要有超时机制,规定好各个环节调用的超时时间,当服务响应时间超过时标记为超时并失败。
      • 比如RPC调用超时时间假设为30,当流量较大时,服务端出现一定数量的慢请求,导致某些客户端有线程阻塞在这些请求上直到30秒超时,当30秒内线程用尽就会导致客户端挂掉。
      • 超时时间的界定比较复杂,尽量通过收集系统调用日志,统计比如99%的响应时间为多久,然后作为依据来界定超时时间。
      • 超时机制是损失少量请求来保证系统整体的可用性
    • 降级:为了保证核心服务的稳定而牺牲非核心服务。比如我们发微博需要先经过内容检查,通过后再完成后续数据库逻辑。前者可能因为各种要求导致逻辑复杂,当并发较高时成为瓶颈,可以暂时关闭来保证主要流程的稳定。
    • 限流:通过对并发请求限速来保护系统。比如对于网站,限制单机吞吐量最大为1000次/秒的请求,超过的请求直接失败。
  3. 系统运维:运维角度是如何避免故障发生,以及发生时如何处理。

    • 灰度发布:指系统非一次性上线,而是按照比例逐步推进,一般是以机器维度。比如,先在10%的机器上变更,然后观察性能指标和错误日志,一段时间正常后再整体上线。
    • 故障演练:指对系统进行破坏性演练,观察局部故障时,系统的整体表现。比如Chaos Monkey等工具,通过在线上系统随机的关闭节点来模拟故障。
  4. 集群化:常见的提升组件可用性的方案就是单点转集群,避免服务器宕机时系统无法提供服务。比如Hadoop早期版本的NameNode是单点,后续NameNode HA扩展为2个NameNode,一个处于Active状态,一个则是StandBy,当Active节点故障StandBy切换状态替换。

  5. 高可扩展的必要性:峰值流量是不可控的,所以我们无法事先预设足够的节点来支持最大并发量。一般会预留30~50%的冗余,但突发事件往往是指数倍的流量突增。

  6. 不管是集群系统还是单机系统,都会存在瓶颈点导致堆机器无法获得正提升,比如系统流量为1000次/秒请求数,数据库也是1000次/秒,流量增加10倍后,服务器扩容了,但数据库变成了瓶颈(还包括缓存、第三方服务、负载均衡、网络带宽等),对于关系型数据库,存储服务是有状态的,扩容涉及到大量的数据迁移,难以扩展。

  7. 存储层扩展:不同业务模块的数据规模差异很大,所以首先要考虑从业务维度拆分存储。当单一的业务数据规模依然过大时,则需要根据数据特征做水平的拆分(分库分表)。拆分的数据库尽量不要使用事务。

  8. 业务层扩展:

    • 业务维度:根据业务模块拆分,不同业务模块基本不依赖对方资源。
    • 重要性维度:根据接口的重要程度,分为核心池和非核心池,优先扩容保障核心池的性能,降级非核心池。
    • 请求来源维度:根据客户端类型来拆分,如客户端、小程序、Web等
  9. 保障系统的高可扩展主要靠拆分

二. 数据库

面试整理——数据库

待整理

问:文件的Page Cache缓存是什么?

zookeeper怎么保证数据一致性的

讲讲你对zk的理解吧

Spring Cloud用到什么东西?
如何实现负载均衡?
服务挂了注册中心怎么判断?

分布式锁的实现你知道的有哪些?具体详细谈一种实现方式

高并发的应用场景,技术需要涉及到哪些?怎样来架构设计?

接着高并发的问题,谈到了秒杀等的技术应用:kafka、redis、mycat等

最后谈谈你参与过的项目,技术含量比较高的,相关的架构设计以及你负责哪些核心编码

部门组织结构是怎样的?
系统有哪些模块,每个模块用了哪些技术,数据怎么流转的?给了我一张纸,我在上面简单画了下系统之间的流转情况
链路追踪的信息是怎么传递的?

SpanId怎么保证唯一性?
RpcContext是在什么维度传递的?
Dubbo的远程调用怎么实现的?

为什么要单独实现一个服务治理框架?
谁主导的?内部还在使用么?
逆向有想过怎么做成通用么?

说下Dubbo的原理?

分布式追踪的上下文是怎么存储和传递的?

Dubbo的RpcContext是怎么传递的?主线程的ThreadLocal怎么传递到线程池?你说的内存泄漏具体是怎么产生的?
线程池的线程是不是必须手动remove才可以回收value?那你说的内存泄漏是指主线程还是线程池?

介绍一下自己对 Netty 的认识,为什么要用。说说业务中,Netty 的使用场景。什么是TCP 粘包/拆包,解决办法。Netty线程模型。Dubbo 在使用 Netty 作为网络通讯时候是如何避免粘包与半包问题?讲讲Netty的零拷贝?巴拉巴拉问了好多,我记得有好几个我都没回答上来,心里想着凉凉了啊。

NginX如何做负载均衡、常见的负载均衡算法有哪些、一致性哈希的一致性是什么意思、一致性哈希是如何做哈希的

你们项目中微服务是怎么划分的,划分粒度怎么确定?
那在实践微服务架构中,有遇到什么问题么?
你们在关于微服务间数据一致性问题,是如何解决的?
你们为什么不用其他的MQ,最终选择了RocketMQ?
为什么RocketMQ没有选择ZooKeeper,而是自己实现了一个NameServer集群?
嗯,理解的不错,Zookeeper在选举的过程中,还能对外提供服务么?
对Paxos算法了解多少?
如果让你来设计一个春晚抢红包架构,你会怎么设计?

你们在微服务中用RPC通信还是REST?
RPC和HTTP的关系是什么?

谈一谈你对微服务架构的理解

你用过哪些RPC框架,讲讲他们优缺点

用过docker么,对容器了解多少

RPC是什么,如何实现?发送请求之后如何阻塞?让你来设计你会怎么做?这里讨巧,回答用restful做,但是同样问了发送之后怎么确定收到了这个请求的数据

消息队列怎么实现?异步回调你会怎么做,讲一下你要怎么实现

问:分布式事务的控制?

问:分布式锁如何设计?

分布式锁要解决的问题是:能够对分布在多台机器中的线程间对共享资源的互斥访问。

实现方案:

  1. 基于数据库:分布式共同访问同一个库,利用数据库本身的排他性(行锁)来达到互斥访问,对于MySQL来说加锁和释放锁性能较差,不适合生产环境。
  2. 基于ZooKeeper:ZK数据存放在内存,基于ZK的顺序节点、临时节点、Watch机制等能非常好的实现分布式锁。
  3. 基于Redis:基于Redis的消费订阅、数据超时时间、Lua脚本等来实现。

问:分布式 session 如何设计?

问:分布式ID?

9种 分布式ID生成方式

三. zookeeper

问:zookeeper 的 ZAB 协议工作原理?

问:zookeeper 的 Watcher 机制?

问:zookeeper 的数据存储?

问:zookeeper 的负载均衡算法?

问:eureka 的相关原理,和 zookeeper 的比较?

问:LVS(4层与7层)原理?

  • 由前端虚拟负载均衡器和后端真实服务器群组成;
  • 请求发送给虚拟服务器后其根据包转发策略以及负载均衡调度算法转发给真实服务器
  • 所谓四层(lvs,f5)就是基于IP+端口的负载均衡;七层(nginx)就是基于URL等应用层信息的负载均衡

问:zookeeper实现分布式锁?

(1):利用节点名称唯一性来实现,加锁时所有客户端一起创建节点,只有一个创建成功者获得锁,解锁时删除节点。

(2):利用临时顺序节点实现,加锁时所有客户端都创建临时顺序节点,创建节点序列号最小的获得锁,否则监视比自己序列号次小的节点进行等待

(3):方案2比1好处是当zookeeper宕机后,临时顺序节点会自动删除释放锁,不会造成锁等待;

(4):方案1会产生惊群效应(当有很多进程在等待锁的时候,在释放锁的时候会有很多进程就过来争夺锁)。

(5):由于需要频繁创建和删除节点,性能上不如redis锁

四. ElasticSearch

Elasticsearch 基于“倒排索引”来实现,倒排索引是指将记录中的某些列做分词,然后形成的分词与记录 ID 之间的映射关系。

问:你们公司的ES集群,一个node一般会分配几个分片?

问:Elasticsearch是如何实现Master选举的?

问:你是如何做写入调优的?

问:什么是脑裂?如何避免脑裂?

问:Elasticsearch对于大数据量(上亿量级)的聚合如何实现?

问:ES主分片数量可以在后期更改吗?为什么?

问:如何监控集群状态?

问:ElasticSearch中的副本是什么?

问:ES更新数据的执行流程?

问:shard里面是什么组成的?

问:ElasticSearch中的分析器是什么?

问:客户端在和集群连接时,如何选择特定的节点执行请求的?

问:Elasticsearch中的倒排索引是什么?

问:什么是索引?索引(名词) 一个索引(index)

问:详细描述一下Elasticsearch更新和删除文档的过程?

问:elasticsearch 的系统架构及读写过程?

问:elasticsearch 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?

-————————————–

参考:

🔗 高并发系统设计 40 问