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的区别
维度 | MySQL | PostgreSQL |
---|---|---|
存储引擎 | 多引擎(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的区别
维度 | query | filter |
---|---|---|
目的 | 计算相关性得分(用于搜索排序) | 精确匹配(是否满足条件) |
缓存 | 不缓存 | 结果缓存(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执行流程:
- 熔断器状态:Closed(正常)、Open(熔断)、Half-Open(探测恢复)。
- 核心参数:
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,再删除缓存):
- 更新数据库。
- 删除缓存(失败时重试或异步补偿)。
-
策略二(延迟双删):
- 删除缓存。
- 更新数据库。
- 延迟再次删除缓存(通过消息队列或定时任务)。
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实现:
- 锁续期:后台线程(Watchdog)定期延长锁持有时间。
- 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. 高并发接口设计
设计步骤:
- 流量评估:预估QPS(如日活100万,峰值QPS≈1157)。
- 多级缓存:本地缓存(Caffeine)+ 分布式缓存(Redis)。
- 异步化:MQ削峰、CompletableFuture并行调用。
- 数据库优化:分库分表、索引优化。
架构示例:
客户端 → 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原理
维度 | Eureka | Consul |
---|---|---|
CAP理论 | AP(高可用性、分区容忍) | CP(一致性、分区容忍) |
健康检查 | 客户端心跳检测 | 服务端主动探测(HTTP/TCP) |
一致性协议 | 无(最终一致性) | Raft协议(强一致性) |
Eureka自我保护机制:当心跳失败比例超阈值,停止剔除实例,防止网络分区误删。