资料汇总

Dubbo

1、Dubbo 简介(主要应用场景、核心功能和核心组件)

Dubbo 是一款高性能、轻量级的开源 RPC 框架,提供服务自动注册、自动发现等高效治理方案,可以和 Spring 框架无缝集成。
好处:
1、透明化的远程方法调用
2、软负载均衡及容错机制
3、服务自动注册与发现
4、提供了完善的服务接口管理与监控功能
使用场景:
1、RPC 分布式服务,拆分应用进行服务化,提高开发效率,调优性能,节省竞争资源
2、配置管理,解决服务的地址信息剧增,配置困难的问题
3、服务依赖,解决服务间依赖关系错踪复杂的问题
4、服务扩容,解决随着访问量的不断增大,动态扩展服务提供方的机器的问题
核心功能:
1、Remoting:远程通讯,提供对多种 NIO 框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。
2、Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
3、Registry:服务注册中心,服务自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
核心组件:
1、Provider:服务的提供方
2、Consumer:调用远程服务的服务消费方
3、Registry:服务注册和发现的注册中心
4、Monitor:统计服务调用次数和调用时间的监控中心
5、Container:服务运行容器

2、Dubbo 的整体架构设计分层

整体架构

图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。
各层说明:
config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton,以ServiceProxy 为中心,扩展接口为 ProxyFactory
registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为RegistryFactory, Registry, RegistryService
cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为MonitorFactory, Monitor, MonitorService
protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter
exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec
serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool

3、Dubbo 服务注册与发现的流程

服务注册与发现的流程

1、Provider(提供者)绑定指定端口并启动服务
2、Provider连接注册中心,并发本机 IP、端口、应用信息和提供服务信息发送至注册中心存储
3、Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心
4、注册中心根据消费者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。
5、Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。
6、Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer设计的原因:
Consumer 与 Provider 解偶,双方都可以横向增减节点数。注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台
7、去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用
8、服务提供者无状态,任意一台宕掉后,不影响使用

4、Dubbo 的服务调用流程

调用流程

1、Cluster 将 Directory 中的多个 Invoker 伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑
2、Router 负责从多个 Invoker 中按路由规则选出子集,比如读写分离,应用隔离等
3、LoadBalance 负责从多个 Invoker 中选出具体的一个用于本次调用,选的过程包含了负载均衡算法

5、Dubbo 的通信框架

Dubbo 默认使用 Netty 框架,也是推荐的选择,另外还集成有Mina、Grizzly

6、Dubbo 的注册中心

Dubbo目前支持4种注册中心(multicast,zookeeper,redis,simple),推荐使用Zookeeper

7、Dubbo 的支持协议

1、Dubbo 协议(官方推荐协议)
优点:采用NIO复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用)
缺点:大文件上传时,可能出现问题(不使用 Dubbo 文件上传)
2、RMI(Remote Method Invocation)协议
优点:JDK 自带的能力。可与原生 RMI 互操作,基于 TCP 协议
缺点:偶尔连接失败.
3、Hessian协议
优点:可与原生 Hessian 互操作,基于 HTTP 协议
缺点:需 hessian.jar 支持,http 短连接的*开销大8

8、Dubbo 的序列化框架

Hessian 序列化:是修改过的 hessian lite,默认启用
json 序列化:使用 FastJson 库
java 序列化:JDK 提供的序列化,性能不理想
dubbo 序列化:未成熟的高效 java 序列化实现,不建议在生产环境使用

9、Dubbo 的负载均衡策略

1、Random LoadBalance,随机(默认的负载均衡策略)
RandomLoadBalance 是加权随机算法的具体实现,可以完全随机,也可以按权重设置随机概率。
2、RoundRobin LoadBalance,轮循
可以轮询和加权轮询。存在响应慢的提供者会累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
3、LeastActive LoadBalance,最少活跃调用数
活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求。此时应优先将请求分配给该服务提供者。
4、ConsistentHash LoadBalance,一致性 Hash
一致性 Hash 算法,相同参数的请求一定分发到一个 provider 上去。provider 挂掉的时候,会基于虚拟节点均匀分配剩余的流量,抖动不会太大。

10、 Dubbo 的集群容错策略

Dubbo 官网提出总共有六种容错策略
1、Failover Cluster:失败自动切换,当出现失败,重试其它服务器。(默认)
2、Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
3、Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
4、Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
5、Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=”2”来设置最大并行数。
6、Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0 开始支持) 通常用于通知所有提供者更新缓存或日志等本地资源信息。
总结:在实际应用中查询语句容错策略建议使用默认 Failover Cluster,而增删改建议使用 Failfast Cluster 或者使用 Failover Cluster(retries=”0”)策略,防止出现数据重复添加等等其它问题!建议在设计接口时候把查询接口方法单独做一个接口提供查询。

ZooKeeper

1、ZooKeeper 是什么

ZooKeeper 是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

2、ZooKeeper 提供了什么

  1. 文件系统
  2. 通知机制

3、ZooKeeper 工作机制

ZooKeeper 从设计模式角度来理解:就是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,ZK 就将负责通知已经在 ZK 上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。


工作机制

4、ZooKeeper 特性

特性
  • ZooKeeper:一个领导者(leader),多个跟随者(follower)组成的集群。
  • Leader 负责进行投票的发起和决议,更新系统状态。
  • Follower 用于接收客户请求并向客户端返回结果,在选举 Leader 过程中参与投票。
  • 集群中只要有半数以上节点存活,Zookeeper 集群就能正常服务。
  • 全局数据一致(单一视图):每个 Server 保存一份相同的数据副本,Client 无论连接到哪个 Server,数据都是一致的。
  • 顺序一致性: 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
  • 原子性: 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
  • 实时性,在一定时间范围内,client 能读到最新数据。
  • 可靠性: 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。

5、Zookeeper 设计目标

简单的数据结构 :Zookeeper 使得分布式程序能够通过一个共享的树形结构的名字空间来进行相互协调,即Zookeeper 服务器内存中的数据模型由一系列被称为ZNode的数据节点组成,Zookeeper 将全量的数据存储在内存中,以此来提高服务器吞吐、减少延迟的目的。
可以构建集群 :Zookeeper 集群通常由一组机器构成,组成 Zookeeper 集群的每台机器都会在内存中维护当前服务器状态,并且每台机器之间都相互通信。
顺序访问 :对于来自客户端的每个更新请求,Zookeeper 都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序。
高性能 :Zookeeper 和 Redis 一样全量数据存储在内存中,100% 读请求压测 QPS 12-13W

6、Zookeeper 文件系统

Zookeeper 提供一个多层级的节点命名空间(节点称为 znode)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。
Zookeeper 为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得 Zookeeper 不能用于存放大量的数据,每个节点的存放数据上限为1M。

7、四种类型的数据节点 Znode

  • PERSISTENT-持久节点
    除非手动删除,否则节点一直存在于 Zookeeper 上
  • EPHEMERAL-临时节点
    临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper 连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。
  • PERSISTENT_SEQUENTIAL-持久顺序节点
    基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
  • EPHEMERAL_SEQUENTIAL-临时顺序节点
    基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

8、ZAB 协议?

ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议。
ZAB 协议包括两种基本的模式:崩溃恢复和消息广播。
当整个 zookeeper 集群刚刚启动或者 Leader 服务器宕机、重启或者网络故障导致不存在过半的服务器与 Leader 服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的 Leader 服务器,然后集群中 Follower 服务器开始与新的 Leader 服务器进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader 服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。

9、Zookeeper 的典型应用场景

ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能

10、核心概念

  • ZooKeeper 本身就是一个分布式程序(只要半数以上节点存活,ZooKeeper 就能正常服务)。
  • 为了保证高可用,最好是以集群形态来部署 ZooKeeper,这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么 ZooKeeper 本身仍然是可用的。
  • ZooKeeper 将数据保存在内存中,这也就保证了高吞吐量和低延迟(但是内存限制了能够存储的容量不太大,此限制也是保持 znode 中存储的数据量较小的进一步原因)。
  • ZooKeeper 是高性能的。在“读”多于“写”的应用程序中尤其的高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景。)
  • ZooKeeper 底层其实只提供了两个功能:管理(存储、读取)用户程序提交的数据和为用户程序提交数据节点监听服务

11、Zookeeper Watcher 机制

Zookeeper 允许用户在指定节点上注册一些 Watcher,当 Znode 发生变化时,将触发并删除一个 watch。当 watch 被触发时客户端会收到一个数据包,指示 znode 已经被修改。如果客户端和 ZooKeeper 服务器之间的连接中断,客户端将收到本地通知。该机制是 Zookeeper 实现分布式协调服务的重要特性。
3.6.0中的新增功能:客户端还可以在 znode 上设置永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发已注册 znode 以及所有子 znode 的更改。
ZooKeeper 客户端(Client)会在指定的节点(/Configuration/B)上注册一个 Watcher,ZNode 上的 B 被更新的时候,服务端就会通知 Client1 和 Client2。


watch 机制

12、Zookeeper 的会话(Session)

Session 指的是 ZooKeeper 服务器与客户端会话。
在 ZooKeeper 中,一个客户端连接是指客户端和服务器之间的一个 TCP 长连接。客户端启动的时候,首先会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期也开始了。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向 Zookeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watch 事件通知。
Session 作为会话实体,用来代表客户端会话,其包括 4 个属性:

  • SessionID,用来全局唯一识别会话;
  • TimeOut,会话超时事件。客户端在创造 Session 实例的时候,会设置一个会话超时的时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在 sessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效;
  • TickTime,下次会话超时时间点;
  • isClosing,当服务端如果检测到会话超时失效了,会通过设置这个属性将会话关闭。

13、Zookeeper 的ACL

Zookeeper 采用 ACL(Access Control Lists)策略来进行权限控制,类似于 UNIX 文件系统的权限控制。Zookeeper 定义了如下 5 种权限:

  • CREATE: 创建子节点的权限
  • READ: 获取节点数据和子节点列表的权限
  • WRITE: 更新节点数据的权限
  • DELETE: 删除子节点的权限
  • ADMIN: 设置节点ACL的权限
    其中尤其需要注意的是,CREATE 和 DELETE 这两种权限都是针对子节点的权限控制。

14、Zookeeper 的集群角色

最典型集群模式:Master/Slave 模式(主备模式)。在这种模式中,通常 Master 服务器作为主服务器提供写服务,其他的 Slave 从服务器通过异步复制的方式获取 Master 服务器最新的数据提供读服务。
但是,在 ZooKeeper 中没有选择传统的 Master/Slave 概念,而是引入了Leader、Follower 和 Observer 三种角色。

  • Leader:为客户端提供读和写的服务,负责投票的发起和决议,更新系统状态
  • Follower:为客户端提供读服务,如果是写服务则转发给 Leader。在选举过程中参与投票
  • Observer:为客户端提供读服务器,如果是写服务则转发给 Leader。不参与选举过程中的投票,也不参与“过半写成功”策略。在不影响写性能的情况下提升集群的读性能。此角色是在 zookeeper3.3 系列新增的角色。

server 状态:

  • LOOKING:寻找Leader状态
  • LEADING:领导者状态,表明当前服务器角色是 Leader
  • FOLLOWING:跟随者状态,表明当前服务器角色是 Follower
  • OBSERVING:观察者状态,表明当前服务器角色是 Observer

15、Zookeeper 的选举机制

选举机制
  • 服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING 状态。
  • 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以 id 值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持 LOOKING 状态。
  • 服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
  • 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接受当小弟的命了。
  • 服务器5启动,同4一样当小弟。

Kafka

1、为什么要使用 Kafka ?

缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka 在中间可以起到一个缓冲的作用,把消息暂存在 kafka 中,下游服务就可以按照自己的节奏进行慢慢处理。
解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。
冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅 topic 的服务消费到,供多个毫无关联的业务使用。健壮性: 消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。
异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们 。

2、 Kafka 消费过的消息如何再消费?

kafka 消费消息的 offset 是定义在 zookeeper 中的, 如果想重复消费 kafka 的消息, 可以在 redis 中自己记录 offset 的 checkpoint 点(n 个),当想重复消费消息时,通过读取 redis 中的 checkpoint 点进行 zookeeper 的 offset 重设,这样就可以达到重复消费消息的目的了 。

3、Kafka 的数据是放在磁盘上还是内存上,为什么速度会快

kafka 使用的是磁盘存储,速度快的原因如下。
顺序写入:因为硬盘是机械结构,每次读写都会寻址->写入,其中寻址是一个“机械动作”,它是耗时的。所以硬盘 “讨厌”随机 I/O, 喜欢顺序 I/O。为了提高读写硬盘的速度,Kafka 就是使用顺序 I/O。
Memory Mapped Files(内存映射文件):64 位操作系统中一般可以表示 20G 的数据文件,它的工作原理是直接利用操作系统的 Page 来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上。
Kafka 高效文件存储设计:Kafka 把 topic 中一个 parition 大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。通过索引信息可以快速定位 message 和确定 response 的 大 小。通过 index 元数据全部映射到 memory(内存映射文件),可以避免 segment file 的 IO 磁盘操作。通过索引文件稀疏存储,可以大幅降低 index 文件元数据占用空间大小。

4、Kafka 数据怎么保障不丢失?

这里需要分成三个点说,一个是生产者端,一个消费者端,一个 broker 端 。
生产者数据不丢失
kafka 的 ack 机制:在 kafka 发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常的能够被收到,其中状态有 0,1,-1。
如果是同步模式:ack 设置为 0,风险很大,一般不建议设置为 0。即使设置为 1,也会随着 leader 宕机丢失数据。所以如果要严格保证生产端数据不丢失,可设置为-1 。
如果是异步模式:也会考虑 ack 的状态,除此之外,异步模式下的有个 buffer,通过 buffer 来进行控制数据的发送,有两个值来进行控制,时间阈值与消息的数量阈值,如果 buffer 满了数据还没有发送出去,有个选项是配置是否立即清空 buffer。可以设置为-1,永久阻塞, 也就数据不再生产。异步模式下,即使设置为-1。也可能因为程序员的不科学操作,操作数据丢失,比如 kill -9,但这是特别的例外情况。
注:ack=0:producer 不等待 broker 同步完成的确认,继续发送下一条(批)信息。ack=1(默认):producer 要等待 leader 成功收到数据并得到确认,才发送下一条 message。ack=-1:producer 得到 follwer 确认,才发送下一条数据。
消费者数据不丢失
通过 offset commit 来保证数据的不丢失,kafka 自己记录了每次消费的 offset 数值, 下次继续消费的时候,会接着上次的 offset 进行消费。而 offset 的信息在 kafka0.8 版本之前保存在 zookeeper 中,在 0.8 版本之后保存到 topic 中,即使消费者在运行过程中挂掉了,再次启动的时候会找到 offset 的值,找到之前消费消息的位置,接着消费,由于 offset 的信息写入的时候并不是每条消息消费完成后都写入的,所以这种情况有可能会造成重复消费,但是不会丢失消息 。唯一例外的情况是,我们在程序中给原本做不同功能的两个 consumer 组设置。KafkaSpoutConfig.bulider.setGroupid 的时候设置成了一样的 groupid,这种情况会导致这两个组共享同一份数据,就会产生组 A 消费 partition1,partition2 中的消息,组 B 消费 partition3 的消息,这样每个组消费的消息都会丢失,都是不完整的。为了保证每个组都独享一份消息数据,groupid 一定不要重复才行。
kafka 集群中的 broker 的数据不丢失
每个 broker 中的 partition 我们一般都会设置有 replication(副本)的个数,生产者写入的时候首先根据分发策略(有 partition 按 partition,有 key 按 key,都没有轮询)写入到 leader 中,follower(副本)再跟 leader 同步数据,这样有了备份,也可以保证消息数据的不丢失 。

5、Kafka 数据分区和消费者的关系?

每个分区只能由同一个消费组内的一个消费者(consumer)来消费,可以由不同的消费组的消费者来消费,同组的消费者则起到并发的效果

6、采集数据为什么选择 Kafka?

在采集层,主要可以使用 Flume, Kafka 等技术 。
Flume:Flume 是管道流方式,提供了很多的默认实现,让用户通过参数部署,及扩展 API 。
Kafka:Kafka 是一个可持久化的分布式的消息队列。 Kafka 是一个非常通用的系统。你可以有许多生产者和很多的消费者共享多个主题 Topics 。
相比之下,Flume 是一个专用工具被设计为旨在往 HDFS,HBase 发送数据。它对 HDFS 有特殊的优化,并且集成了 Hadoop 的安全特性。所以,Cloudera 建议如果数据被多个系统消费的话,使用 kafka;如果数据被设计给 Hadoop 使用,使用 Flume

7、Kafka 的数据 offset 读取流程?

连接 ZK 集群,从 ZK 中拿到对应 topic 的 partition 信息和 partition 的 Leader 的相关信息连接到对应 Leader 对应的 brokerconsumer 将自己保存的 offset 发送给 LeaderLeader 根据 offset 等信息定位到 segment(索引文件和日志文件)根据索引文件中的内容,定位到日志文件中该偏移量对应的开始位置读取相应长度的数据并返回给 consumer 。

8、Kafka 重启是否会导致数据丢失?

kafka 是将数据写到磁盘的,一般数据不会丢失。但是在重启 kafka 过程中,如果有消费者消费消息,那么 kafka 如果来不及提交 offset,可能会造成数据的不准确(丢失或者重复消费)

9、Kafka 宕机了如何解决?

先考虑业务是否受到影响:
kafka 宕机了,首先我们考虑的问题应该是所提供的服务是否因为宕机的机器而受到影响,如果服务提供没问题,如果实现做好了集群的容灾机制,那么这块就不用担心了。
节点排错与恢复:
想要恢复集群的节点,主要的步骤就是通过日志分析来查看节点宕机的原因,从而解决,重新恢复节点 。

10、为什么 Kafka 不支持读写分离?

在 Kafka 中,生产者写入消息、消费者读取消息的操作都是与 leader 副本进行交互的,从 而实现的是一种主写主读的生产消费模型。
Kafka 并不支持主写从读,因为主写从读有 2 个很明显的缺点 :
数据一致性问题:
数据从主节点转到从节点必然会有一个延时的时间窗口,这个时间窗口会导致主从节点之间的数据不一致。某一时刻,在主节点和从节点中 A 数据的值都为 X, 之后将主节点中 A 的值修改为 Y,那么在这个变更通知到从节点之前,应用读取从节点中的 A 数据的值并不为最新的 Y,由此便产生了数据不一致的问题 。
延时问题:
类似 Redis 这种组件,数据从写入主节点到同步至从节点中的过程需要经历 网络→主节点内存→网络→从节点内存 这几个阶段,整个过程会耗费一定的时间。而在 Kafka 中,主从同步会比 Redis 更加耗时,它需要经历 网络→主节点内存→主节点磁盘→网络→从节点内存→从节点磁盘 这几个阶段 。对延时敏感的应用而言,主写从读的功能并不太适用 。
而 kafka 的主写主读的优点就很多了:
可以简化代码的实现逻辑,减少出错的可能; 将负载粒度细化均摊,与主写从读相比, 不仅负载效能更好,而且对用户可控 ; 没有延时的影响 ; 在副本稳定的情况下,不会出现数据不一致的情况 。

11、Kafka 消息数据积压,Kafka 消费能力不足怎么处理?

如果是 Kafka 消费能力不足,则可以考虑增加 Topic 的分区数,并且同时提升消费组的消费者数量,消费者数=分区数。(两者缺一不可)
如果是下游的数据处理不及时: 提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间<生产速度),使处理的数据小于生产的数据,也会造成数据积压 。

12、Kafka 单条日志传输大小?

kafka 对于消息体的大小默认为单条最大值是 1M 但是在我们应用场景中, 常常会出现一条消息大于 1M,如果不对 kafka 进行配置。则会出现生产者无法将消息推送到 kafka 或消费者无法去消费 kafka 里面的数据, 这时我们就要对 kafka 进行配置

13、Kafka 内部如何保证顺序,结合外部组件如何保证消费者的顺序?

kafka 只能保证 partition 内是有序的,但是 partition 间的有序是没办法的。我们常用的做法,是从业务上把需要有序的打到同一个 partition

Redis

1、Redis为什么快

  • 完全基于内存操作
  • 使⽤单线程,避免了线程切换和竞态产生的消耗
  • 基于⾮阻塞的IO多路复⽤机制
  • C语⾔实现,优化过的数据结构,基于⼏种基础的数据结构,redis做了⼤量的优化,性能极⾼

2、Redis 的数据类型

Redis 支持五种数据类型:string(字符串),hash(哈希),list( 列表),set(集合) 及sorted set(有序集合)

3、Redis的持久化

Redis持久化⽅案分为RDB和AOF两种。

  • RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发
  • AOF(append only file)持久化:以独立日志的方式记录每次写命令, 重启时再重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
    RDB恢复速度快,AOF实时性好,数据一致性强
  • 一般来说, 如果想达到足以媲美数据库的数据安全性,应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。
  • 如果可以接受数分钟以内的数据丢失,那么可以只使用 RDB 持久化。

4、缓存穿透、缓存击穿、缓存雪崩的区别和解决方案

缓存穿透:访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。
解决方案:

  • 采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
  • 拦截器,接⼝层增加校验,如给id做校验,id<=0的直接拦截。
  • 从cache和db都取不到,可以将key-value写为key-null,设置较短过期时间,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
    缓存击穿:一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。
    解决方案:
  • 设置热点数据永远不过期。
  • 加互斥锁。
    缓存雪崩:大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
    解决方案:
  • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中。
  • 设置热点数据永远不过期。

5、Redis过期键的删除策略

Redis采用的是定期删除+惰性删除策略

  • 为什么不用定时删除策略?
    定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.
  • 定期删除+惰性删除是如何工作的呢?
    定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
    于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
  • 采用定期删除+惰性删除就没其他问题了么?
    不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。

6、Redis内存淘汰策略

内存淘汰策略

注意这里的6种机制,volatile 和allkeys 规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据, 后面的lru、ttl 以及random 是三种不同的淘汰策略,再加上一种no-enviction 永不回收的策略。

7、数据不一致问题及其解决方案

问题:先操作缓存,在写数据库成功之前,如果有读请求发生,可能导致旧数据入缓存,引发数据不一致。
解决方案
方案1:Redis设置key的过期时间。
方案2:采用延时双删策略。

  • 先淘汰缓存
  • 再写数据库(这两步和原来一样)
  • 休眠n毫秒,再次淘汰缓存
    这么做,可以将n毫秒内所造成的缓存脏数据,再次删除。(为何是n毫秒?需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。当然这种策略还要考虑redis和数据库主从同步的耗时。)

8、如何处理热key?

对热key的处理,最关键的是对热点key的监控,可以从这些端来监控热点key:

  • 客户端 客户端其实是距离key“最近”的地方,因为Redis命令就是从客户端发出的,例如在客户端设置全局字典(key和调用次数),每次调用Redis命令时,使用这个字典进行记录。
  • 代理端 像Twemproxy、Codis这些基于代理的Redis分布式架构,所有客户端的请求都是通过代理端完成的,可以在代理端进行收集统计。
  • Redis服务端 使用monitor命令统计热点key是很多开发和运维人员首先想到,monitor命令可以监控到Redis执行的所有命令。
    只要监控到了热key,对热key的处理就简单了:
  • 把热key打散到不同的服务器,降低压⼒
  • 加⼊⼆级缓存,提前加载热key数据到内存中,如果redis宕机,⾛内存查询

9、Redis应用:分布式锁

setnx命令 + 锁超时释放,Redis 2.8 版本中加入了 set 指令的扩展参数,使得 setnx 和expire 指令可以一起执行

10、Redis的高可用

Redis保证高可用主要有三种方式:主从、哨兵、集群
主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为 主节点(master),后者称为 从节点(slave)。且数据的复制是 单向 的,只能由主节点到从节点。Redis 主从复制支持 主从同步 和 从从同步 两种,后者是 Redis 后续版本新增的功能,以减轻主节点的同步负担。

Redis Sentinel ,它由两部分组成,哨兵节点和数据节点:
哨兵节点: 哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据,对数据节点进行监控。
数据节点: 主节点和从节点都是数据节点;
在复制的基础上,哨兵实现了 自动化的故障恢复 功能,下面是官方对于哨兵功能的描述:

  • 监控(Monitoring): 哨兵会不断地检查主节点和从节点是否运作正常。
  • 自动故障转移(Automatic failover): 当 主节点 不能正常工作时,哨兵会开始 自动故障转移操作,它会将失效主节点的其中一个 从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
  • 配置提供者(Configuration provider): 客户端在初始化时,通过连接哨兵来获得当前 Redis 服务的主节点地址。
  • 通知(Notification): 哨兵可以将故障转移的结果发送给客户端。
    其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移。而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

前面说到了主从存在高可用和分布式的问题,哨兵解决了高可用的问题,而集群就是终极方案,一举解决高可用和分布式问题

  • 数据分区: 数据分区 (或称数据分片) 是集群最核心的功能。集群将数据分散到多个节点,一方面 突破了 Redis 单机内存大小的限制,存储容量大大增加;另一方面 每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
  • 高可用: 集群支持主从复制和主节点的 自动故障转移 (与哨兵类似),当任一节点发生故障时,集群仍然可以对外提供服务。

11、布隆过滤器

布隆过滤器,它是一个连续的数据结构,每个存储位存储都是一个bit,即0或者1, 来标识数据是否存在。存储数据的时时候,使用K个不同的哈希函数将这个变量映射为bit列表的的K个点,把它们置为1。


布隆过滤器

我们判断缓存key是否存在,同样,K个哈希函数,映射到bit列表上的K个点,判断是不是1:如果全不是1,那么key不存在;如果都是1,也只是表示key可能存在。
布隆过滤器也有一些缺点:
它在判断元素是否在集合中时是有一定错误几率,因为哈希算法有一定的碰撞的概率,不支持删除元素。

12、一致性Hash算法

将整个 Hash 值空间组织成一个虚拟的圆环,然后将缓存节点的 IP 地址或者主机名做 Hash 取值后,放置在这个圆环上。当我们需要确定某一个 Key 需 要存取到哪个节点上的时候,先对这个 Key 做同样的 Hash 取值,确定在环上的位置,然后按照顺时针方向在环上“行走”,遇到的第一个缓存节点就是要访问的节点


一致性Hash算法

你可能感兴趣的:(资料汇总)