新一轮拷打

采用的什么将分布式缓存同步到本地缓存?1.Redis Pub/sub 2.MQ

分布式定时任务广播的原理,啥协议通知到多台机子上?

Redis Pub/sub基于啥协议。。

RPC原理

流程

客户端调用 → 代理层 → 序列化 → 网络传输 → 服务端接收 → 反序列化 → 实际方法调用

  1. 服务端启动,并监听端口。
  2. 客户端stub通过动态代理调用服务接口的方法。
  3. 动态代理将调用信息封装成请求消息,序列化后发送给服务端。
  4. 服务端stub接收请求,反序列化,通过服务名和方法名找到对应的实现方法,使用反射执行方法。
  5. 服务端将执行结果序列化后返回给客户端。
  6. 客户端接收响应,反序列化后得到结果,返回给调用者。

动态代理层(客户端)

方法调用 → JDK动态代理拦截 → 构造Request → 序列化 → 网络发送 → 等待响应

服务暴露层(服务端)

设计思路:
1. 扫描标注了@RpcService的类
2. 将服务注册到本地服务映射表
3. 启动网络服务器监听请求
4. 根据请求调用对应服务方法

工作流程:
接收请求 → 反序列化 → 查找服务 → 反射调用 → 返回结果

网络传输层

传输方案选择:
方案1: 基于Netty的NIO长连接
  - 优点:高性能,支持连接复用
  - 实现:ChannelPool管理连接,心跳保活

方案2: 基于HTTP的短连接  
  - 优点:简单,穿透性好
  - 实现:RestTemplate或HttpClient

服务注册发现

注册中心选择:
- ZooKeeper: 强一致性,可靠性高
- Nacos: 易用性好,功能丰富
- Redis: 性能高,部署简单

注册流程:
1. 服务端启动时向注册中心注册服务
2. 客户端订阅服务变化
3. 注册中心通知客户端服务列表变更

3. 详细工作流程

3.1 服务端启动流程

1. 扫描@RpcService注解,构建服务映射表
2. 启动网络服务器,绑定端口
3. 向注册中心注册服务元数据
   - 服务名称: userService
   - 服务地址: 192.168.1.100:8080
   - 服务版本: 1.0.0
   - 权重: 100
4. 启动心跳线程,定期上报健康状态
5. 进入请求监听循环

3.2 客户端调用流程

1. 通过动态代理创建服务接口的代理对象
2. 从注册中心获取服务提供者列表
3. 根据负载均衡策略选择服务实例
4. 构造RPC请求对象:
   - 生成唯一Request ID
   - 设置服务名、方法名
   - 序列化方法参数
5. 通过网络发送请求
6. 同步等待服务端响应(支持超时)
7. 反序列化响应结果,返回给调用方

3.3 服务端处理流程

1. 网络层接收请求字节流
2. 协议解码,验证Magic Number和版本
3. 根据序列化类型反序列化请求体
4. 从服务映射表查找对应的服务实例
5. 通过反射调用目标方法
6. 捕获方法执行结果或异常
7. 构造响应对象并序列化
8. 通过原连接返回响应

还有 容错/限流/熔断/负载均衡措施

序列化指request或response序列化为字节流以便传输

RPC 服务端Provider提供的服务是如何注册的 如何被客户端consumer发现的?

服务注册与发现通常涉及三个角色:服务提供者(Provider)、服务消费者(Consumer)和注册中心(Registry)。

  1. 服务提供者启动时,将自己的信息(如服务名、IP、端口、协议等)注册到注册中心。
  2. 服务消费者启动时,从注册中心获取服务提供者的地址列表,并建立连接。
  3. 当服务提供者发生变更(如上下线)时,注册中心会通知服务消费者。

具体步骤:

一、服务注册(Provider端):

  • 服务提供者启动后,会向注册中心注册自己提供的服务。
  • 注册信息通常包括:服务接口名、版本号、分组、IP地址、端口、协议等。
  • 注册中心会保存这些信息,并建立服务名到提供者地址列表的映射。

二、服务发现(Consumer端):

  • 服务消费者启动时,会向注册中心订阅自己所需的服务。
  • 注册中心将服务提供者的地址列表返回给消费者。
  • 消费者根据负载均衡策略从地址列表中选择一个提供者进行调用。

三、动态感知:

  • 注册中心会检测服务提供者的健康状态,如果提供者下线或故障,注册中心会将其从地址列表中移除。
  • 注册中心会通知订阅了该服务的消费者,更新本地缓存的服务地址列表。

xxljob

监控机子不可用:

xxl-job由调度器和执行器两部分组成,调度器是xxl-job的大脑,何时触发任务,哪个机器执行任务,这都是调度器去决策的。执行器是打工人,是干具体事的,运行在业务服务器上。

执行器在ExecutorRegistryThread类中启动一个线程,告诉调度器一声“我来了”,不管上报成功与否,都会睡眠30s,睡醒了,要继续告诉调度器一声“我还在”,就这样不断的报备。一旦jvm关闭,执行器告诉调度器一声“我走了”。

调度器在JobRegistryMonitorHelper类中启动一个线程,它会将超过90s没有上报的执行器,从xxl_job_registry表中删除,然后更新xxl_job_group表的address_list字段。

链接:https://juejin.cn/post/7051964061474357285 来源:稀土掘金

故障转移:Admin 维护着一个健康的执行器列表,当需要进行故障转移时,可以从这个列表中选择一个合适的“替补”来接管任务。

确保一个任务不会被重复执行:分布式调度系统引入了分布式锁机制,确保在同一时间只有一个 Admin 节点能够对某个任务进行调度。在 XXL-JOB 中,这个锁是利用数据库的行级锁来实现的。源码:XXL-JOB 的调度线程会定期扫描数据库中需要执行的任务。在每次扫描并处理之前,它会尝试获取一个数据库锁。只有成功获取锁的线程才能继续,否则会跳过本次调度,从而避免重复执行。

在阿里实习,那中间件了解哪个?早知道说MQ了

你知道像Clickhouse他们底层的引擎吗?知道MPP吗

讲讲你理解的MCP

RAG检索出来的不对如何处理

mysql 索引(a,b) sql a>1 and b>1会走哪些索引?索引(a,b) 非叶子节点存的是什么

会部分使用 (a, b) 复合索引,并且对前导列 a 进行索引范围扫描。

  1. 范围扫描开始:在索引的B+树上,找到第一个满足 a < 1 的条目。
  2. 顺序遍历与过滤:从这个条目开始,沿着叶子节点的链表向后顺序扫描(这就是“范围扫描”),直到遇到第一个 a >= 1 的记录为止。
  3. 应用 b 的过滤条件:在步骤2的扫描过程中,对于每一条索引记录,会检查它的 b 字段是否满足 b < 1。

关键点: 步骤3中检查 b 字段的方式,在有了索引下推 优化后,是在存储引擎层直接进行的,而不是把所有 a < 1 的记录都拿到Server层再过滤。这大大减少了需要回表(如果查询需要返回其他不在索引中的列)或向上传递的数据量。

如果有个mysql表里面数据非常不均匀,比如人种,那么黑种人就非常少,造成查询很慢。除了建索引、分表、存缓存还没有其他方法?

索引下推

在没有索引下推的情况下,执行一个查询(比如:使用复合索引(a,b)和条件a<1 AND b<1)的步骤是:

  1. 存储引擎根据索引(如果使用索引)定位到满足a<1的第一行,然后返回所有满足a<1的索引行(注意:这里只利用索引的a列进行范围扫描,然后返回整个索引行,包括b列)。
  2. 然后,Server层再根据WHERE条件中的b<1来过滤这些行。

但是,如果使用了索引下推,那么过程就变成了:

  1. 存储引擎根据索引定位到满足a<1的第一行。
  2. 然后,存储引擎会检查索引中的b列(因为b列也在索引中)是否满足b<1。如果不满足,则跳过该行,继续下一行;如果满足,则返回该行给Server层。

这样,索引下推将本应在Server层进行的过滤条件(b<1)下推到了存储引擎层,从而减少了存储引擎层需要返回给Server层的行数,提高了查询性能。

索引下推的适用条件

  • 只能用于复合索引,因为单列索引不存在“下推”另一列的条件。
  • 适用于WHERE条件中包含了索引中的列,但是这些列不能全部被用于索引范围扫描(比如,只有前导列用于范围扫描,后续列用于过滤)。索引列的部分条件无法用于快速定位,但可以在扫描过程中过滤
  • 查询需要回表(访问主键索引)时,能显著减少回表次数
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务