岚图面试纪要

1. Redis的底层原理和IO模型

底层数据结构与原理
  • 字符串(SDS, Simple Dynamic String)​

    • 结构体:包含长度(len)、空闲空间(free)和字符数组(buf)。
    • 优化:预分配空间减少内存重分配次数。例如,追加操作时若剩余空间不足,会分配 新长度 * 2 的空间。
    struct sdshdr {
      int len;     // 已用长度
      int free;    // 剩余空间
      char buf[];  // 数据存储
    };
  • 哈希表(Dict)​

    • 渐进式Rehash:在扩容时维护新旧两个哈希表,逐步迁移数据,避免单次迁移阻塞。
    • 碰撞处理:链地址法(每个桶存储链表)。
  • 跳跃表(Skiplist)​

    • 层数随机:节点层数由概率决定(如幂次定律),最高32层。
    • 查找复杂度:平均O(logN),最坏O(N)。
IO模型(单线程Reactor模式)​
  • 事件驱动架构

    • 文件事件处理器:使用epoll监听多个套接字,将事件分发给对应的处理器(如连接应答处理器、命令请求处理器)。
    • 时间事件:定时任务(如键过期、持久化),通过无序链表存储,每次循环遍历执行到期事件。
  • Java实现多路复用(NIO Selector)​

    // 创建Selector并注册事件
    Selector selector = Selector.open();
    ServerSocketChannel serverSocket = ServerSocketChannel.open();
    serverSocket.bind(new InetSocketAddress(6379));
    serverSocket.configureBlocking(false);
    serverSocket.register(selector, SelectionKey.OP_ACCEPT);
    
    while (true) {
      selector.select();
      Set<SelectionKey> selectedKeys = selector.selectedKeys();
      Iterator<SelectionKey> iter = selectedKeys.iterator();
      while (iter.hasNext()) {
        SelectionKey key = iter.next();
        iter.remove();
        if (key.isAcceptable()) handleAccept(selector, serverSocket);
        else if (key.isReadable()) handleRead(key);
      }
    }

2. MySQL与PostgreSQL的区别

维度MySQLPostgreSQL
存储引擎多引擎(InnoDB、MyISAM)单一引擎(支持自定义扩展)
事务隔离REPEATABLE-READ(默认)READ COMMITTED(默认),支持SSI
复制主从异步复制物理/逻辑复制,同步复制支持
JSON支持JSON类型(半结构化)JSONB(二进制存储,支持索引)
性能场景高并发读优化(如简单查询)复杂查询、写密集型场景

示例:PostgreSQL JSONB查询

-- 创建表并插入JSONB数据
CREATE TABLE orders (id SERIAL PRIMARY KEY, data JSONB);
INSERT INTO orders (data) VALUES ('{"product": "Laptop", "price": 999}');

-- 查询价格大于500的订单
SELECT * FROM orders WHERE data @> '{"price": 999}';

3. ES的query和filter的区别

维度queryfilter
目的计算相关性得分(用于搜索排序)精确匹配(是否满足条件)
缓存不缓存结果缓存(bitset)
性能较慢(需计算得分)更快(直接匹配,利用缓存)

底层执行流程

  • Query Context:解析查询生成Query树,计算相关性得分(TF-IDF、BM25)。
  • Filter Context:生成BitSet(位图标记匹配文档),结果缓存。

组合查询示例

{
  "query": {
    "bool": {
      "must": [{ "match": { "title": "elastic" }}],  // query
      "filter": [{ "term": { "status": "published" }}]  // filter
    }
  }
}

4. Guava RateLimiter的实现原理

核心机制
  • 令牌桶算法:按固定速率(QPS)生成令牌,请求获取令牌后执行。
  • 平滑突发限制(SmoothBursty)​:允许突发流量(如预热期)。
  • 预热模式(SmoothWarmingUp)​:逐步增加速率,避免冷启动压力。

源码解析

// 令牌生成逻辑
void sync(long nowMicros) {
  storedPermits = Math.min(maxPermits, storedPermits + (nowMicros - nextFreeTicketMicros) * stableIntervalMicros);
}

// 请求获取令牌
boolean canAcquire(long timeout) {
  long waitTime = reserveAndGetWaitLength(permits, nowMicros);
  return waitTime <= timeout;
}

示例:创建RateLimiter

RateLimiter limiter = RateLimiter.create(10.0); // 每秒10个令牌
if (limiter.tryAcquire()) {
  // 执行业务逻辑
} else {
  // 限流处理
}

5. Spring Cloud熔断器实现逻辑

Hystrix执行流程
  1. 熔断器状态:Closed(正常)、Open(熔断)、Half-Open(探测恢复)。
  2. 核心参数
    • requestVolumeThreshold(触发熔断的最小请求数)。
    • errorThresholdPercentage(错误率阈值)。

Hystrix配置示例

hystrix:
  command:
    default:
      circuitBreaker:
        requestVolumeThreshold: 20
        errorThresholdPercentage: 50
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

熔断逻辑代码

public class OrderServiceCommand extends HystrixCommand<String> {
  protected String run() {
    return callExternalService(); // 业务逻辑
  }
  
  protected String getFallback() {
    return "Fallback Response"; // 降级逻辑
  }
}

6. Redis缓存双写一致性问题

解决方案
  • 策略一(先更新DB,再删除缓存)​

    1. 更新数据库。
    2. 删除缓存(失败时重试或异步补偿)。
  • 策略二(延迟双删)​

    1. 删除缓存。
    2. 更新数据库。
    3. 延迟再次删除缓存(通过消息队列或定时任务)。

Binlog监听实现​(使用Canal):

CanalConnector connector = CanalConnectors.newClusterConnector("zkHosts", "destination", "", "");
connector.connect();
connector.subscribe(".*\\..*");
Message message = connector.getWithoutAck(100);
for (Entry entry : message.getEntries()) {
  RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
  // 解析出主键ID,更新Redis
  redis.del("cache_key:" + id);
}

7. Redis分布式锁实现

Redisson实现
  1. 锁续期:后台线程(Watchdog)定期延长锁持有时间。
  2. Lua脚本原子操作
    if (redis.call('exists', KEYS[1]) == 0) then
      redis.call('hincrby', KEYS[1], ARGV[2], 1);
      redis.call('pexpire', KEYS[1], ARGV[1]);
      return nil;
    end;

Java代码示例

RLock lock = redisson.getLock("myLock");
lock.lock(10, TimeUnit.SECONDS);
try {
  // 业务逻辑
} finally {
  lock.unlock();
}

8. 高并发接口设计

设计步骤
  1. 流量评估:预估QPS(如日活100万,峰值QPS≈1157)。
  2. 多级缓存:本地缓存(Caffeine)+ 分布式缓存(Redis)。
  3. 异步化:MQ削峰、CompletableFuture并行调用。
  4. 数据库优化:分库分表、索引优化。

架构示例

客户端 → CDN → API网关 → 服务集群(线程池隔离) 
                   ↓               ↓
                Redis Cluster → 数据库代理(MyCAT)

9. 缓存穿透与布隆过滤器

布隆过滤器原理
  • 结构:位数组(m位)+ k个哈希函数。
  • 写入:元素哈希k次,置位数组对应位置为1。
  • 查询:所有哈希位均为1则可能存在(可能误判)。

Guava实现

BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(), 1000000, 0.01);
filter.put("key1");
boolean exists = filter.mightContain("key1");

10. Eureka与Consul的区别及CAP原理

维度EurekaConsul
CAP理论AP(高可用性、分区容忍)CP(一致性、分区容忍)
健康检查客户端心跳检测服务端主动探测(HTTP/TCP)
一致性协议无(最终一致性)Raft协议(强一致性)

Eureka自我保护机制:当心跳失败比例超阈值,停止剔除实例,防止网络分区误删。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值