短信接口被狂刷怎么处理

短信接口被狂刷怎么处理

"紧急止损→多层防护→业务优化→监控复盘"

第一阶段:紧急止损🔥(黄金 30 分钟)

先把问题压下来,避免损失扩大,这是优先级最高的操作:

  1. 立即降级:通过配置中心将短信接口切换为 "测试模式",返回成功但实际不发送短信;或直接熔断接口
  2. IP 黑名单:在 Nginx 层快速封禁异常请求 IP 段,拦截 90% 以上的恶意流量
  3. 限流兜底:在网关层开启全局限流(如每秒 100 次),防止服务被打垮
  4. 临时关停:如果以上措施无效,直接下线短信发送功能,优先保障核心业务可用

第二阶段:多层防护体系🛡️(全链路拦截)

建立从前端到后端、从网关到业务的立体防护网,层层过滤恶意请求:

各层具体实现要点
防护层级 核心技术 拦截效果 实现难度
前端层 图形验证码、短信倒计时、按钮禁用 拦截 80% 普通刷量 ★☆☆☆☆
Nginx 层 IP 限流、Referer 校验、User-Agent 过滤 拦截 15% 爬虫流量 ★★☆☆☆
网关层 令牌桶限流、API 签名、IP 黑白名单 拦截 4% 恶意攻击 ★★★☆☆
业务层 手机号频次限制、设备指纹、行为风控 拦截 0.9% 高级攻击 ★★★★☆
第三方层 平台自带风控、日发送量上限 最后一道防线 ★☆☆☆☆

第三阶段:业务侧优化🎯(从根源解决)

技术防护只能治标,业务逻辑优化才能治本:

  1. 频次限制:同一手机号 60 秒内只能发 1 次,24 小时内最多 5 次,1 个月内最多 20 次
  2. 场景隔离:注册、登录、找回密码等不同场景分别限流,避免一个场景被刷影响全局
  3. 验证升级:对异常 IP / 手机号强制要求滑块验证码或语音验证码
  4. 成本分摊:对高风险操作(如批量发送)引入付费机制,提高攻击者成本
  5. 号码校验:对接运营商号码库,过滤虚拟号、物联网卡和风险号码

整理了面试真题、每日技术知识点、系统学习路线,√X搜「Rain的Java 大神之路」

每天拆一个知识点,陪你悄悄变强,有空来坐坐。


第四阶段:监控与事后复盘📊

  1. 实时监控:搭建短信发送量、成功率、失败率、异常 IP 请求数等指标的大盘,设置阈值告警
  2. 日志审计:记录所有短信发送请求的 IP、手机号、设备信息、时间戳,便于事后溯源
  3. 攻击分析:定期分析攻击特征,更新风控规则,形成闭环
  4. 压力测试:模拟恶意刷量场景,验证防护体系的有效性
核心技术细节(加分项✨)
  • 限流算法 :推荐使用令牌桶算法(支持突发流量),而非漏桶算法;分布式环境下用 Redis+Lua 脚本实现原子性限流
  • 缓存设计 :手机号频次限制用 Redis 的INCR+EXPIRE命令,过期时间自动重置
  • 防刷技巧:使用 Redis 的HyperLogLog统计每日不同手机号数量,节省内存;用布隆过滤器快速过滤无效手机号
  • 灰度发布:新的风控规则先在小流量范围验证,再全量上线
面试官可能追问的问题及回答思路
Q:分布式环境下如何保证限流的准确性?

A:使用 Redis+Lua 脚本实现原子性操作,避免并发问题;同时采用 "最终一致性" 思想,允许极小误差

Q:攻击者使用代理 IP 池怎么办?

A:结合设备指纹、手机号、行为特征进行多维度风控,而不仅仅依赖 IP

Q:Redis 挂了怎么办?

A:采用 Redis 集群保证高可用;同时在本地内存中保留一份降级限流规则,作为兜底

核心代码实现(带技术亮点标注✨)

1. Redis+Lua 分布式令牌桶限流(最核心!面试必问)

技术亮点:Lua 脚本保证原子性,避免并发计数偏差;支持突发流量,性能是分布式锁的 10 倍以上

lua 复制代码
-- 令牌桶限流Lua脚本(KEYS[1]=限流key, ARGV[1]=桶容量, ARGV[2]=令牌生成速率/秒, ARGV[3]=当前时间戳)
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

-- 获取桶内剩余令牌和上次刷新时间
local bucket = redis.call('HMGET', key, 'tokens', 'last_refresh')
local tokens = tonumber(bucket[1]) or capacity
local last_refresh = tonumber(bucket[2]) or now

-- 计算生成的新令牌数
local delta = math.max(0, now - last_refresh) * rate
tokens = math.min(capacity, tokens + delta)

-- 尝试获取令牌
if tokens >= 1 then
    redis.call('HMSET', key, 'tokens', tokens - 1, 'last_refresh', now)
    redis.call('EXPIRE', key, 3600) -- 1小时过期
    return 1 -- 获取成功
else
    return 0 -- 获取失败
end
java 复制代码
// Java调用端
@Service
public class RateLimitService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String LUA_SCRIPT = "上面的Lua脚本内容";
    
    /**
     * 令牌桶限流
     * @param key 限流维度(ip:xxx / phone:xxx / device:xxx)
     * @param capacity 桶容量
     * @param rate 每秒生成令牌数
     * @return 是否通过限流
     */
    public boolean tryAcquire(String key, int capacity, int rate) {
        long now = System.currentTimeMillis() / 1000;
        Long result = redisTemplate.execute(
            new DefaultRedisScript<>(LUA_SCRIPT, Long.class),
            Collections.singletonList(key),
            String.valueOf(capacity),
            String.valueOf(rate),
            String.valueOf(now)
        );
        return result != null && result == 1;
    }
}
2. 手机号频次限制(Redis 原子操作)

技术亮点:INCR+EXPIRE 组合实现滑动窗口,避免多线程并发问题;不同场景隔离限流

java 复制代码
@Service
public class SmsFrequencyService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    // 不同场景限流配置(可配置化)
    private static final Map<String, int[]> SCENE_LIMIT = Map.of(
        "register", new int[]{1, 60, 5, 86400}, // 注册:60s1次,24h5次
        "login", new int[]{1, 60, 10, 86400},   // 登录:60s1次,24h10次
        "reset", new int[]{1, 60, 3, 86400}     // 找回密码:60s1次,24h3次
    );
    
    public boolean checkFrequency(String phone, String scene) {
        int[] limit = SCENE_LIMIT.get(scene);
        if (limit == null) return false;
        
        String minuteKey = "sms:freq:" + scene + ":minute:" + phone;
        String dayKey = "sms:freq:" + scene + ":day:" + phone;
        
        // 1分钟内次数检查
        Long minuteCount = redisTemplate.opsForValue().increment(minuteKey);
        if (minuteCount == 1) redisTemplate.expire(minuteKey, limit[1], TimeUnit.SECONDS);
        if (minuteCount > limit[0]) return false;
        
        // 24小时内次数检查
        Long dayCount = redisTemplate.opsForValue().increment(dayKey);
        if (dayCount == 1) redisTemplate.expire(dayKey, limit[3], TimeUnit.SECONDS);
        return dayCount <= limit[2];
    }
}
3. 布隆过滤器快速过滤无效手机号

技术亮点:空间效率极高,1000 万条数据仅需 12MB 内存;O (1) 时间复杂度查询

java 复制代码
// 基于Guava布隆过滤器
@Component
public class PhoneBlacklistFilter {
    private BloomFilter<String> bloomFilter;
    
    @PostConstruct
    public void init() {
        // 预期插入1000万条数据,误判率0.01%
        bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 10_000_000, 0.0001);
        
        // 启动时加载历史黑名单手机号
        List<String> blacklist = phoneBlacklistMapper.selectAll();
        blacklist.forEach(bloomFilter::put);
    }
    
    public boolean mightContain(String phone) {
        return bloomFilter.mightContain(phone);
    }
    
    // 新增黑名单时同步更新布隆过滤器
    public void addBlacklist(String phone) {
        bloomFilter.put(phone);
        phoneBlacklistMapper.insert(phone);
    }
}
4. API 签名验证(防止接口被非法调用)

技术亮点:时间戳 + 随机数防重放,签名算法防篡改,客户端密钥动态更新

java 复制代码
@Service
public class ApiSignService {
    // 客户端密钥(存储在配置中心,支持动态更新)
    @Value("${sms.api.secret}")
    private String apiSecret;
    
    public boolean verifySign(Map<String, String> params) {
        // 1. 检查时间戳是否在5分钟内
        long timestamp = Long.parseLong(params.get("timestamp"));
        if (System.currentTimeMillis() - timestamp > 5 * 60 * 1000) return false;
        
        // 2. 检查随机数是否已使用(防重放)
        String nonce = params.get("nonce");
        if (redisTemplate.hasKey("sms:nonce:" + nonce)) return false;
        redisTemplate.opsForValue().set("sms:nonce:" + nonce, "1", 5, TimeUnit.MINUTES);
        
        // 3. 生成签名并比对
        String clientSign = params.remove("sign");
        String serverSign = generateSign(params, apiSecret);
        return clientSign.equals(serverSign);
    }
    
    private String generateSign(Map<String, String> params, String secret) {
        // 参数按字典序排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        
        // 拼接参数和密钥
        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            sb.append(key).append("=").append(params.get(key)).append("&");
        }
        sb.append("secret=").append(secret);
        
        // MD5加密并转大写
        return DigestUtils.md5DigestAsHex(sb.toString().getBytes()).toUpperCase();
    }
}

技术难点与解决方案(面试加分项🔥)

技术难点 核心问题 解决方案 实现要点
分布式限流计数不准确 多节点同时请求导致计数超发 Redis+Lua 原子操作 所有判断和更新在一个 Lua 脚本中执行,避免竞态条件
代理 IP 池绕过 IP 限流 攻击者使用百万级代理 IP 轮换 多维度联合风控 IP + 手机号 + 设备指纹 + 行为特征(如点击间隔、滑动轨迹)
Redis 宕机导致防刷失效 单点故障引发整个防护体系崩溃 集群 + 本地限流兜底 1. Redis 主从 + 哨兵集群2. 本地内存保留降级限流规则(如单机每秒 10 次)
验证码被打码平台破解 图形验证码识别成本降至 0.01 元 / 条 动态验证码升级 1. 异常用户强制滑块验证码2. 高风险场景使用语音验证码3. 验证码图片添加干扰线和噪点
高并发下 Redis 性能瓶颈 每秒 10 万 + 请求导致 Redis CPU 打满 多级缓存 + 分片 1. 本地缓存热点数据(如 5 分钟内的限流结果)2. Redis 按业务分片部署3. 使用 Redis Pipeline 批量操作
误杀正常用户 风控规则过严影响用户体验 灰度发布 + 白名单 1. 新规则先 10% 流量灰度验证2. 白名单机制放行内部测试和老用户3. 误判申诉通道快速恢复
虚拟号 / 物联网卡批量注册 攻击者使用低成本虚拟号码 运营商号码校验 1. 对接三大运营商号码库2. 过滤 170/171/162 等虚拟号段3. 高风险号码要求实名认证
短信接口被 CC 攻击 每秒数十万请求导致服务雪崩 全链路限流 + 熔断 1. Nginx 层 IP 限流(每秒 10 次)2. 网关层全局限流(每秒 1000 次)3. Sentinel 熔断降级
短信发送链路超时 第三方平台响应慢导致线程阻塞 异步发送 + 超时控制 1. 使用线程池异步发送短信2. 设置第三方接口超时时间(5 秒)3. 失败重试机制(最多 2 次)
攻击溯源困难 无法定位攻击者真实身份 全链路日志审计 1. 记录所有请求的 IP、UA、设备指纹、时间戳2. 日志存储在 ELK 集群,支持快速检索3. 异常请求自动生成攻击报告

面试终极加分回答💯

面试官如果问:你觉得这个方案还有什么可以优化的地方?

我觉得可以从三个方向进一步优化:

  1. 引入 AI 风控:通过机器学习模型分析用户行为特征,自动识别异常请求,比规则风控更精准
  2. 短信通道降级:当主通道被攻击时,自动切换到备用通道,保证业务连续性
  3. 成本优化:对不同风险等级的用户采用不同的验证方式,高风险用户用短信,低风险用户用验证码,降低短信成本

真实面试模拟

真实面试模拟

面试官 😊:

来,咱们聊个很接地气的线上问题------短信接口被狂刷,你会怎么处理? 你可以先整体说说思路。

候选人 🧑‍💻:

好的面试官。这个问题本质是 "用最小成本把正常用户和脚本/黑产区分开,保护短信资费和接口可用性"。

我不会只靠一个点去防,而是按请求的流转路径,从外到内搭一套立体防御。我用张图先给您看下架构:

总共五层:客户端人机识别 → 网关 IP 限流 → 业务多维风控 → 通道熔断兜底 → 事后日志反哺黑名单

面试官 👍:

图很清晰,那咱们一层层拆。先说第一层,前端怎么做?

候选人 🧑‍💻:

第一层必须上行为式验证码,比如滑块、点选,不能用传统的字符验证码,那个早就被打穿了。

前端拿一个 ticket,请求发短信时带上,后端再调第三方服务(极验、网易易盾等)做二次校验。

这一层 ROI 最高,能把绝大部分脚本直接挡掉,后端压力小很多。

面试官 🤔:

嗯,那假如黑产绕过了验证码,比如用打码平台,接下来怎么防?

候选人 🧑‍💻:

那就到了网关层 。这里我针对 IP 维度做高频限流。

Redis + Lua 实现原子化的滑动窗口或令牌桶,比如单个 IP 每分钟最多请求 5 次短信接口。伪代码逻辑是这样的:

lua 复制代码
local key = "sms_limit:ip:" .. ip
local current = redis.call("INCR", key)
if current == 1 then
    redis.call("EXPIRE", key, 60)  -- 60秒窗口
end
if current > 5 then
    return 0  -- 拒绝
end
return 1

如果有 API 网关(Kong/APISIX),直接配插件就行,更低成本。

面试官 💡:

这个思路没问题,但如果对方用大量代理 IP 池来刷,IP 限制不就失效了?

候选人 🧑‍💻:

没错,这时候 IP 限制效果会打折,所以必须上升到业务层多维风控,不只盯 IP。

我一般会拉上这几个维度一起打组合拳:

维度 规则举例 目的
手机号 同手机号 60s 内只能发 1 次,24h 最多 5 次 防单号爆破
用户ID 单用户每日获取上限 10 次 防登录态被盗用刷量
设备指纹 同设备短时间内换不同手机号请求 → 触发风控 识别脚本换号
IP+手机号关联 1 个 IP 在窗口期内请求超过 3 个不同手机号 → 拉黑 IP 猫池设备特征

设备指纹很难批量伪造,加上手机号频控,攻击成本就上去了。风控可以用规则引擎动态调整,不用每次改代码。

面试官 👏:

不错,这就能对付 IP 池了。那假如前端、网关、业务层全被打穿(虽然概率极低),你最底线的保护是什么?

候选人 🧑‍💻:

最后一道防线是短信通道自身的熔断和费用兜底

  • 我会对单分钟发送量设阈值,超了就熔断,直接降级返回"发送失败,请稍后重试",不再调供应商接口。
  • 同时做日费用监控,比如预算 500 元,用掉 80% 钉钉预警,100% 强制关通道。
  • 另外通道隔离很重要,登录、支付等核心业务和营销短信用不同通道,营销被打爆也不影响核心功能。💰
面试官 🧐:

除了实时防御,事后还有什么手段?

候选人 🧑‍💻:

我会把所有短信请求的完整上下文------IP、设备指纹、用户ID、手机号、验证码结果等,全量落日志到 ELK 或 ClickHouse。

离线分析出攻击特征后,反向输出黑名单(IP 段、设备指纹),回灌到线上限流和风控系统里,让整个防御体系"越打越聪明"。🔄

面试官 😄:

可以,整个链路都考虑到了,而且层与层之间有互补。那你觉得在整个方案里,性价比最高的一层是哪里

候选人 🧑‍💻:

绝对是行为式验证码。成本低,接入快,能直接杀掉 80% 以上的自动化脚本,给后面几层降压。

但我不会只靠它,因为一旦被黑产针对性突破,后面必须有纵深防御兜底。

面试官 👍✨:

很好,这个问题就聊到这儿,思路很扎实,场景感也不错。通过!

候选人内心 OS:😌🛡️ 果然,立体防御 yyds。

面试官 🤓:

思路很清晰,那咱们深入一点。你刚才提到业务层的多维风控和通道熔断,能不能挑一两个技术亮点,用代码表达一下你的设计? 不用全写,关键部分就行。

候选人 🧑‍💻:

没问题。我写两个最核心的:一是基于注解的分布式多维限流 ,二是滑动窗口熔断器。这两块代码是直接能扛流量的。

💎 亮点一:声明式多维限流(Redis + Lua + 自定义注解)

我一般会封装一个 @RateLimit 注解,可以灵活指定限流的维度(手机号、IP、用户ID)和阈值,底层用 Redis + Lua 保证原子性。

1. 自定义注解
java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    String key();              // 支持 SpEL,如 "#mobile" "#ip"
    int limit();               // 窗口内最大请求数
    int window();              // 窗口大小,秒
    String message() default "请求过于频繁,请稍后再试";
}
2. AOP 切面 + Lua 原子限流
java 复制代码
@Aspect
@Component
public class RateLimitAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // Lua 脚本:原子性检查并递增
    private static final String LUA_SCRIPT = 
        "local key = KEYS[1] " +
        "local limit = tonumber(ARGV[1]) " +
        "local window = tonumber(ARGV[2]) " +
        "local current = redis.call('INCR', key) " +
        "if current == 1 then " +
        "    redis.call('EXPIRE', key, window) " +
        "end " +
        "if current > limit then " +
        "    return 0 " +  // 超频
        "else " +
        "    return 1 " +  // 放行
        "end";

    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {
        // 解析 SpEL,拿到动态 key
        String dynamicKey = parseSpel(rateLimit.key(), pjp);
        String redisKey = "rate_limit:" + rateLimit.key() + ":" + dynamicKey;

        Long result = redisTemplate.execute(
            new DefaultRedisScript<>(LUA_SCRIPT, Long.class),
            Collections.singletonList(redisKey),
            String.valueOf(rateLimit.limit()),
            String.valueOf(rateLimit.window())
        );

        if (result == 0) {
            throw new BusinessException(rateLimit.message()); // 统一异常处理
        }
        return pjp.proceed();
    }

    // SpEL 解析略,Spring 自带工具可做
}
3. 在短信接口上使用
java 复制代码
@RestController
public class SmsController {

    // 手机号维度:60秒内1次
    @RateLimit(key = "#mobile", limit = 1, window = 60, message = "验证码已发送,请稍后再试")
    // IP 维度:60秒内5次(可以和上面组合,或另外配置网关限流)
    @RateLimit(key = "#request.remoteAddr", limit = 5, window = 60, message = "请求频繁")
    @PostMapping("/send-sms")
    public Result sendSms(@RequestParam String mobile, HttpServletRequest request) {
        // ... 发送逻辑
    }
}

亮点:原子性由 Lua 保证,不会出现并发超发;声明式注解让业务代码零侵入,不同维度可以随意叠加;Redis 瓶颈极低,单机轻松扛万级 QPS。💪

💎 亮点二:短信通道滑动窗口熔断器

当调用短信供应商之前,需要实时判断当前通道是否过载。我用一个线程安全的滑动窗口计数器实现轻量熔断,不依赖外部组件。

java 复制代码
public class SlidingWindowCircuitBreaker {
    // 窗口大小(秒)
    private final int windowSize;
    // 窗口内最大允许请求数
    private final int maxRequests;
    // 每个时间槽的计数器(数组索引按秒映射)
    private final AtomicInteger[] buckets;
    // 窗口起始时间戳(秒)
    private volatile long startTime;
    // 总计数器,用于快速判断
    private final AtomicInteger totalCount = new AtomicInteger(0);

    public SlidingWindowCircuitBreaker(int windowSize, int maxRequests) {
        this.windowSize = windowSize;
        this.maxRequests = maxRequests;
        this.buckets = new AtomicInteger[windowSize];
        for (int i = 0; i < windowSize; i++) {
            buckets[i] = new AtomicInteger(0);
        }
        this.startTime = System.currentTimeMillis() / 1000;
    }

    /**
     * 尝试获取一个许可,返回 true 代表未熔断,可发送;false 代表需降级
     */
    public synchronized boolean tryAcquire() {
        long now = System.currentTimeMillis() / 1000;
        // 如果窗口过期,重置
        if (now - startTime >= windowSize) {
            resetWindow(now);
        }
        // 清理过期槽位(滑动)
        slideWindow(now);

        if (totalCount.get() >= maxRequests) {
            return false;  // 熔断
        }
        // 对应槽位计数+1
        int index = (int) (now % windowSize);
        buckets[index].incrementAndGet();
        totalCount.incrementAndGet();
        return true;
    }

    private void slideWindow(long now) {
        long expiredSlots = now - startTime;
        for (long i = 0; i < expiredSlots && i < windowSize; i++) {
            int idx = (int) ((startTime + i) % windowSize);
            int oldVal = buckets[idx].getAndSet(0);
            totalCount.addAndGet(-oldVal);
        }
        startTime = now;
    }

    private void resetWindow(long now) {
        for (AtomicInteger bucket : buckets) {
            bucket.set(0);
        }
        totalCount.set(0);
        startTime = now;
    }
}
在短信发送服务中使用:
java 复制代码
@Service
public class SmsService {
    // 1分钟窗口内最多发送100条,超过就熔断降级
    private SlidingWindowCircuitBreaker breaker = 
        new SlidingWindowCircuitBreaker(60, 100);

    public void sendSms(String mobile, String content) {
        if (!breaker.tryAcquire()) {
            // 熔断降级:直接返回失败提示或扔队列
            throw new SmsCircuitBreakException("短信通道繁忙,请稍后重试");
        }
        // 调用供应商发送...
    }
}

亮点:纯内存实现,零外部依赖,极低延迟;synchronized 在这种低频控制场景完全够用,且滑动窗口精确到秒级,避免临界突发流量把通道打爆。😎

面试官 🧐:

代码写得挺扎实。那你结合刚才的方案和代码,总结一下这个场景的技术难点和对应的解决方案

候选人 🧑‍💻:

好的,核心难点和拆解方案我用一张表归纳:

技术难点 具体表现 解决方案 对应代码/模块
自动化脚本突破 黑产用无头浏览器+打码平台直接调用接口 行为式验证码 + 二次校验,强制人机识别 客户端验证码 ticket 校验
高并发下计数不准确 多实例/多线程同时递增计数导致超发 Redis + Lua 原子操作,单线程执行计数 @RateLimit + Lua 脚本
IP 池代理绕过 大量代理 IP 使得 IP 限流失效 多维度组合拳:设备指纹 + 手机号 + 用户ID 联合风控 多维注解叠加,风控规则引擎
短信通道成本雪崩 即便内部限流被突破,短信资费仍可能爆炸 通道级熔断降级 + 日费用监控 + 核心/营销通道隔离 滑动窗口熔断器,费用告警
风控规则僵化 攻防对抗不断变化,写死代码无法快速响应 规则引擎动态加载,日志离线分析反哺黑名单 Drools/自研规则引擎 + ELK 分析管道
分布式一致性 分布式环境下限流状态要统一 Redis 集中式计数器,通过 Lua 保证读写原子性 所有限流 key 落 Redis

这些方案环环相扣,既保证线上实时防护的刚性 ,又保留事后学习和动态调整的柔性,落地起来坑相对少。

面试官 😄👍:

不错,从理论到代码,再到难点复盘,这一整套很完整。这个问题你拿下了!

面试结束后的彩蛋 🥚:

候选人(内心):😌 幸亏平时真这样挡过线上攻击,Lua 脚本的原子性、设备指纹的权重、熔断的滑动窗口,这些都是填过的坑啊~

整理了面试真题、每日技术知识点、系统学习路线,√X搜「Rain的Java 大神之路」

每天拆一个知识点,陪你悄悄变强,有空来坐坐。

相关推荐
江南风月1 小时前
3分钟快速上手日志审计系统 WGLOG v2.2 更新了什么
运维·服务器·网络
孙克旭_1 小时前
Docker 镜像构建|Vue+SpringBoot+Go 多语言项目 Dockerfile 案例
linux·运维·vue.js·spring boot·docker·dockerfile
2602_959960922 小时前
谢飞机面试大厂:Spring Boot、JVM、Redis、Kafka、微服务与音视频搜索场景求生实录
java·jvm·spring boot·redis·面试题
Zane1994122 小时前
CAS 与原子类:Java 如何实现无锁编程
java·开发语言
Lost of 程序猿2 小时前
AOP 实战:面向切面编程从理论到落地
后端·asp.net·aop·面向切片变成
略略略咯咯2 小时前
AI玩具-study
java
接口不宕机2 小时前
外贸公司实战:利用 1688API 自动化监控竞品价格,解决采购定价痛点
运维·自动化
Lost of 程序猿2 小时前
ASP.NET Core 认证授权实战:从 JWT 到 Policy,设计一套企业级 RBAC 权限系统
后端·asp.net
Lost of 程序猿2 小时前
ASP.NET Core 后台任务全景:从 BackgroundService 到 Channel 队列,再到分布式调度
后端·asp.net·.netcore