4、接入层设计与实现:协议适配、连接池管理、流量整形与限流
接入层,说白了就是风控系统的「大门」。
所有交易请求,不管从哪来、用什么协议,都得先过这一关。我见过不少系统,风控逻辑写得挺漂亮,结果接入层先崩了——连接数打满、协议解析出错、流量直接把服务冲垮。嗯,这章咱们就把这扇「门」设计好。
4.1 协议适配:让不同「方言」都能对话
交易渠道五花八门。有的用HTTP,有的走TCP长连接,还有的用WebSocket做实时推送。你想想看,如果每种协议都单独写一套处理逻辑,那维护成本得多高?
我个人习惯的做法是:抽象一个统一的协议层接口,把协议差异隔离在适配器里。
核心思路: 定义统一的 Request/Response 模型,各协议适配器负责「翻译」成内部标准格式。
// 统一协议适配器接口
public interface ProtocolAdapter {
// 将原始请求解析为内部标准请求
StandardRequest parse(byte[] rawData);
// 将内部标准响应编码为协议特定格式
byte[] encode(StandardResponse response);
// 判断是否支持该协议
boolean supports(String protocolType);
}
我在项目中遇到过最头疼的事:某银行渠道用的HTTP,但报文格式是自定义的二进制。嗯,这时候适配器就派上用场了——你只需要写一个 BinaryHttpAdapter,其他逻辑完全不用动。
4.1.1 HTTP 适配
HTTP 是最常见的。我建议用 Servlet Filter 或 Spring Interceptor 做统一拦截。注意一点:不要把业务逻辑写在 Filter 里,只做协议转换和基础校验。
4.1.2 TCP 适配
TCP 长连接常用于内部系统对接。这里有个坑:粘包/拆包问题。我曾经因为没处理好这个,线上数据全乱了。解决方案是用 LengthFieldBasedFrameDecoder(Netty)或者自定义分隔符。
4.1.3 WebSocket 适配
WebSocket 适合需要服务端主动推送的场景,比如交易状态实时通知。我个人习惯用 Spring WebSocket + STOMP 协议,省心不少。
4.2 连接池管理:别让连接成为瓶颈
连接池,说白了就是「复用」。每次请求都新建TCP连接?那性能肯定完蛋。
我见过最夸张的情况:某系统没配连接池,高峰期每秒新建3000个连接,直接把系统端口耗尽了。嗯,这就是典型的「连接泄漏」。
避坑指南: 我曾经因为连接池的 maxTotal 配得太大,导致数据库连接数被打满。记住:连接池不是越大越好,要根据实际并发和响应时间算。
| 参数 | 推荐值 | 说明 |
|---|---|---|
| maxTotal | 50-200 | 最大连接数,根据压测结果调整 |
| maxIdle | 10-30 | 最大空闲连接,避免资源浪费 |
| minIdle | 5-10 | 最小空闲连接,应对突发流量 |
| maxWaitMillis | 1000-3000 | 获取连接的超时时间,单位毫秒 |
我建议用 Apache Commons Pool2 或 HikariCP。HikariCP 性能最好,但 Commons Pool2 更灵活。怎么选?看你的场景——如果只是数据库连接,HikariCP 就够了;如果还要管理 Redis、MQ 等连接,Commons Pool2 更通用。
4.3 流量整形与限流:给系统装上「安全阀」
流量整形,说白了就是「削峰填谷」。限流则是「挡在门外」。两者配合,才能让系统稳如老狗。
你想想看,双十一零点那波流量,如果不做限流,系统直接被打穿。我经历过一次,那叫一个惨——数据库连接池爆满,应用服务器CPU 100%,最后只能重启。从那以后,我再也不敢轻视限流了。
4.3.1 常用限流算法
- 计数器算法: 最简单,但存在「临界突变」问题。比如1秒内限100次,前0.9秒没请求,后0.1秒来了100次,系统照样扛不住。
- 滑动窗口算法: 把时间窗口切分成小格子,每个格子独立计数。比计数器平滑,但精度越高内存开销越大。
- 漏桶算法: 请求先进入桶里,以固定速率流出。适合「平滑流量」,但无法应对突发。
- 令牌桶算法: 以固定速率往桶里放令牌,请求来了拿令牌。允许一定程度的突发,我比较推荐这个。
我的经验: 风控系统建议用 令牌桶 + 滑动窗口 组合。令牌桶控制平均速率,滑动窗口防止突发。具体实现可以用 Guava RateLimiter 或 Sentinel。
// 使用 Guava RateLimiter 实现令牌桶
RateLimiter limiter = RateLimiter.create(100.0); // 每秒100个令牌
public boolean tryAcquire() {
// 尝试获取令牌,超时100ms
return limiter.tryAcquire(100, TimeUnit.MILLISECONDS);
}
4.3.2 流量整形策略
流量整形不只是限流,还包括:
- 排队等待: 请求先入队列,按优先级或时间顺序处理。我建议用
Disruptor或LinkedBlockingQueue。 - 降级处理: 超过阈值后,返回「系统繁忙」或走简化流程。比如风控评分可以降级为「快速模式」。
- 动态调整: 根据系统负载自动调整限流阈值。我做过一个方案:CPU > 80% 时,限流阈值自动降低20%。
核心原则: 限流不是目的,保证核心交易能正常处理才是。所以,限流要分优先级——VIP用户的请求,阈值可以高一些。
4.4 知识体系总览
下面这张图,把接入层的核心逻辑串起来了。你可以把它当作设计时的「检查清单」。
从图上你能看到:请求先经过协议适配层,转成统一格式;然后进入连接池管理层,复用已有连接;最后经过流量整形与限流层,决定是放行还是排队。三层各司其职,缺一不可。
一个小建议: 接入层的每个组件都要做 熔断。比如连接池满了,不要一直等,直接返回「服务暂不可用」。我习惯用 Resilience4j 做熔断,轻量又好用。
好了,接入层就聊到这儿。记住:这扇「大门」设计好了,后面的风控逻辑才能安心跑。别嫌麻烦,该做的限流、连接池、协议适配,一个都不能少。
公众号:蓝海资料掘金营,微信deep3321