当前位置: 首页 > news >正文

【缓存技术】深入分析如果使用好缓存及注意事项


Java 架构师缓存深度实践指南:策略、陷阱与高并发场景实战


一、缓存设计核心策略
1. 缓存选型与场景适配

缓存选型需结合业务场景、数据规模、性能要求等多维度评估:

场景推荐方案工具/技术案例
高频读、极少写本地缓存Caffeine、Guava Cache电商平台商品分类缓存
分布式共享分布式缓存Redis、Hazelcast用户会话信息共享
高并发读、容忍不一致多级缓存(本地+分布式)Caffeine + Redis秒杀系统库存缓存
海量数据、低成本持久化缓存Redis + RocksDB新闻App历史文章归档

案例1:电商商品分类缓存
商品分类数据变更频率低(每天更新1-2次),但访问量极高。

// 使用 Caffeine 实现本地缓存
LoadingCache<String, List<Category>> categoryCache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(1, TimeUnit.HOURS).build(key -> categoryDao.loadFromDB());public List<Category> getCategories(String type) {return categoryCache.get(type);
}

2. 缓存模式选择

根据业务需求选择缓存模式:

  • Cache-Aside (Lazy Loading)
    适用场景:读多写少,允许短暂不一致。

    public Product getProduct(String id) {Product product = cache.get(id);if (product == null) {product = db.query("SELECT * FROM products WHERE id = ?", id);cache.put(id, product, ttl); // 设置合理TTL}return product;
    }
    
  • Write-Through (同步更新)
    适用场景:写操作频繁,需强一致性。

    public void updateProduct(Product product) {db.update(product);  // 先写DBcache.put(product.getId(), product); // 同步更新缓存
    }
    
  • Write-Behind (异步批量写)
    适用场景:高吞吐写入,允许短暂数据丢失。

    public void logUserAction(UserAction action) {cache.put(action.getId(), action); // 立即写入缓存asyncQueue.add(() -> db.batchInsert(action)); // 异步批量写入DB
    }
    

二、缓存问题防御体系
1. 缓存穿透:非法请求穿透防御

场景:攻击者频繁请求不存在的数据(如负库存ID)。
解决方案:布隆过滤器 + 空值缓存。

案例2:用户黑名单拦截

// 初始化布隆过滤器(100万数据,误判率1%)
BloomFilter<String> blacklistFilter = BloomFilter.create(Funnels.stringFunnel(), 1_000_000, 0.01);// 预热数据
userBlacklistDao.loadAll().forEach(blacklistFilter::put);public boolean isUserBlocked(String userId) {if (!blacklistFilter.mightContain(userId)) {return false; // 快速放行合法用户}Boolean blocked = redis.get("blacklist:" + userId);return blocked != null ? blocked : false;
}
2. 缓存雪崩:批量失效防御

场景:促销活动结束,大量优惠券缓存同时过期。
解决方案:随机过期时间 + 永不过期结合异步更新。

案例3:促销活动缓存

// 基础过期时间 + 随机偏移(0~300秒)
int baseTtl = 3600;
int randomTtl = baseTtl + new Random().nextInt(300);
redisTemplate.opsForValue().set("promotion:2023-sale", data, randomTtl, TimeUnit.SECONDS);// 后台线程定期更新
@Scheduled(fixedRate = 30 * 60 * 1000)
public void refreshPromotionCache() {PromotionData data = promotionService.loadLatest();redisTemplate.opsForValue().set("promotion:2023-sale", data);
}
3. 缓存击穿:热点Key失效防御

场景:明星离婚新闻导致热点文章缓存失效,DB被击穿。
解决方案:互斥锁重建 + 逻辑过期时间。

案例4:热点新闻缓存

public News getNews(String newsId) {News news = redis.get(newsId);if (news == null || news.isExpired()) {RLock lock = redisson.getLock("news_lock:" + newsId);if (lock.tryLock()) {try {news = newsDao.get(newsId); // 双重检查redis.set(newsId, news, 24, TimeUnit.HOURS);} finally {lock.unlock();}} else {return getNewsFromLocalCache(newsId); // 返回本地备份}}return news;
}

三、一致性保障方案
1. 双删策略

场景:订单状态更新后,缓存与DB不一致。
方案:先删缓存 → 更新DB → 延迟再删。

案例5:订单状态同步

public void updateOrderStatus(String orderId, String status) {// 1. 删除缓存redis.delete("order:" + orderId);// 2. 更新数据库orderDao.updateStatus(orderId, status);// 3. 延迟1秒再删scheduledExecutor.schedule(() -> {redis.delete("order:" + orderId);}, 1, TimeUnit.SECONDS);
}
2. 基于Binlog的最终一致性

工具链:Canal → Kafka → 缓存更新服务。

案例6:商品价格同步

-- MySQL表结构
CREATE TABLE products (id VARCHAR(64) PRIMARY KEY,price DECIMAL(10,2),update_time TIMESTAMP
);
// Canal监听Binlog
@CanalEventListener
public class ProductPriceListener {@ListenPoint(table = "products")public void onUpdate(ProductPriceChangeEvent event) {kafkaTemplate.send("product-price-update", event.getId());}
}// 消费者更新缓存
@KafkaListener(topics = "product-price-update")
public void updateCache(String productId) {Product product = productDao.get(productId);redis.set("product:" + productId, product);
}

四、性能优化技巧

1. 内存优化:序列化优化(Kryo vs JSON)

在缓存系统中,序列化方式直接影响内存占用和网络传输效率。以下是 Kryo 与 JSON 的深度对比及实战案例:


1.1 核心特性对比
特性KryoJSON(Jackson/Gson)
序列化格式二进制文本(UTF-8)
序列化速度快(比 JSON 快 5-10 倍)
反序列化速度快(比 JSON 快 3-5 倍)
序列化后大小小(比 JSON 小 50-70%)
跨语言支持需特定实现(如 Kryo-Netty)天然支持
可读性无(二进制不可读)高(文本可读)
兼容性需管理注册 ID(类结构变更易破坏兼容性)高(字段名映射,兼容增减字段)
适用场景高性能、高吞吐的内部服务通信跨语言交互、调试日志、配置文件

1.2 性能测试数据

测试对象:10,000 个 User 对象(含 id, name, email, age 字段)
环境:JDK 17,Intel i7-12700H,32GB RAM

指标KryoJacksonGson
序列化时间 (ms)124552
反序列化时间 (ms)153843
序列化后大小 (KB)89215225

1.3 实战案例:用户信息缓存优化

场景:某社交平台用户服务缓存 1 千万用户数据,需降低内存占用并提升吞吐量。

原始方案(JSON)

// 使用 Jackson 序列化
public byte[] serializeUser(User user) {return objectMapper.writeValueAsBytes(user);
}public User deserializeUser(byte[] data) {return objectMapper.readValue(data, User.class);
}

问题

  • 单个用户序列化后占 215 KB,总内存消耗约 2.15 TB。
  • 高峰期反序列化延迟导致接口 P99 达 150 ms。

优化方案(Kryo)

// 配置 Kryo 池(线程安全)
public class KryoPoolFactory {private static final Pool<Kryo> pool = new Pool<>(true, false) {@Overrideprotected Kryo create() {Kryo kryo = new Kryo();kryo.register(User.class); // 显式注册类return kryo;}};public static byte[] serialize(User user) {Kryo kryo = pool.obtain();try (ByteArrayOutputStream bos = new ByteArrayOutputStream();Output output = new Output(bos)) {kryo.writeObject(output, user);output.flush();return bos.toByteArray();} finally {pool.free(kryo);}}public static User deserialize(byte[] data) {Kryo kryo = pool.obtain();try (Input input = new Input(data)) {return kryo.readObject(input, User.class);} finally {pool.free(kryo);}}
}

优化效果

  • 单个用户序列化后占 89 KB,总内存消耗降至 890 GB(节省 58.6%)。
  • 反序列化 P99 延迟降至 30 ms,吞吐量提升 3 倍。

1.4 兼容性管理策略

Kryo 的类注册机制在字段变更时易导致兼容性问题,需通过以下方式规避:

  1. 固定注册 ID
    kryo.register(User.class, 10); // 固定 ID,避免自动生成
    
  2. 字段兼容规则
    • 新增字段:反序列化时自动填充默认值(如 null)。
    • 删除字段:旧数据中的多余字段自动忽略。
  3. 版本升级流程
    • 灰度发布:新版本服务逐步替换,兼容新旧数据格式。
    • 双写策略:升级期间同时写入新旧格式数据。

1.5 最佳实践建议
场景推荐序列化方案理由
内部服务间高性能缓存(如Redis)Kryo极致性能,节省内存和带宽
跨语言交互(如前端/第三方API)JSON(Jackson)天然兼容,调试方便
配置文件/日志存储JSON(Gson)可读性强,修改灵活
高版本兼容性要求Protobuf/Thrift强 Schema 管理,兼容性更优

2. 其他内存优化技巧
  • 压缩算法:对 JSON 等文本协议启用 LZ4 压缩,体积减少 60-70%。
    // 使用 LZ4 压缩 JSON
    public byte[] compress(String json) {return LZ4Factory.fastestInstance().fastCompressor().compress(json.getBytes());
    }
    
  • 数据结构优化
    • 频繁更新的对象 → 使用 Redis Hash 存储独立字段。
    • 分页查询 → 使用 Redis ZSet 存储排序数据。

总结

在缓存系统中,序列化选择是性能优化的杠杆点

  • Kryo 以二进制高效性碾压 JSON,适合内部高性能场景,但需管理类注册和版本兼容性。
  • JSON 凭借可读性和跨语言支持,仍是开放生态的首选。

实际项目中,可结合 多序列化策略:核心高频数据用 Kryo,边缘数据用 JSON,并通过统一接口封装,实现灵活切换。


五、运维与监控体系

1. 核心监控指标与工具链

有效的监控是保障缓存系统稳定性的基石,需关注以下核心指标:

指标报警阈值监控工具应对措施
缓存命中率< 90%Prometheus + Grafana检查缓存键设计,预热热点数据
内存使用率> 85%Redis INFO 命令清理无用键,扩容或优化数据结构
网络带宽> 80% 峰值Zabbix优化批量操作,增加节点分片
平均响应时间> 50msElastic APM检查慢查询,优化序列化/反序列化逻辑

案例7:电商大促期间缓存监控
某电商平台在双十一期间通过 Grafana 实时监控 Redis 集群状态:

  • 看板配置
    • Redis 内存使用率(按节点展示)。
    • 缓存命中率(按业务线分类)。
    • 命令延迟分布(P50、P90、P99)。
  • 报警规则
    • 内存使用率超过 85% → 触发自动清理脚本。
    • 命中率低于 90% → 通知运维团队检查缓存预热任务。

2. 容灾与故障恢复

多活架构设计

                          ┌─────────────┐│  北京 Region ││ Redis Cluster│└──────┬──────┘│ 数据同步┌──────▼──────┐│  上海 Region ││ Redis Cluster│└─────────────┘
  • 优势:单机房故障时自动切换流量。
  • 工具:Redis Replica + 哨兵模式,或商业方案如 AWS ElastiCache Multi-AZ。

降级预案

  • 一级降级:关闭非核心业务缓存(如商品推荐),优先保障交易链路。
  • 二级降级:返回静态默认值(如库存显示“充足”)。
  • 三级降级:启用限流熔断(如 Sentinel 或 Hystrix)。

案例8:缓存故障降级实战
某金融 App 在 Redis 集群宕机时触发降级:

  1. Nginx 本地缓存返回最近 5 分钟的用户余额(通过 Lua 脚本实现)。
  2. 核心交易功能降级至数据库,非核心功能(如账单明细)暂时不可用。
  3. 运维团队通过 Kafka 消息异步恢复缓存数据。

六、架构设计注意事项

1. 缓存分层设计

典型多级缓存架构

客户端 → CDN → Nginx 本地缓存 → Redis 集群 → 数据库
  • CDN:缓存静态资源(如图片、JS/CSS)。
  • Nginx:抗瞬时流量,缓存 API 响应(通过 proxy_cache 模块)。
  • Redis:存储动态数据(如用户资料、库存)。

案例9:新闻详情页多级缓存
某新闻 App 的详情页架构:

  1. CDN:缓存文章正文 HTML(TTL=10分钟)。
  2. Nginx:缓存 JSON API 响应(TTL=1分钟)。
  3. Redis:存储文章元数据(作者、点赞数),实时更新。

2. 冷热数据分离
  • 热数据:高频访问,全内存存储(如 Redis)。
  • 温数据:中低频访问,使用 SSD 缓存(如 Redis + RocksDB)。
  • 冷数据:归档至对象存储(如 AWS S3),支持按需加载。

案例10:社交平台历史消息存储

  • 热数据:最近 7 天的聊天记录 → Redis。
  • 温数据:7 天至 1 年的记录 → Redis + RocksDB。
  • 冷数据:1 年以上的记录 → 压缩后存储至 S3,访问时解压加载。

3. 缓存预热策略

定时预热

@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
public void preloadDailyHotData() {List<String> hotKeys = hotKeyPredictor.predict();hotKeys.parallelStream().forEach(key -> {Value value = db.load(key);cache.put(key, value);});
}

事件驱动预热

@KafkaListener(topics = "product-view")
public void handleProductView(String productId) {// 实时统计访问量Long views = redis.opsForValue().increment("product:views:" + productId);if (views > 1000) {// 触发预热cacheAsyncLoader.load(productId);}
}

七、综合案例分析

案例11:秒杀系统缓存设计

挑战

  • 瞬时 10 万 QPS 访问特定商品库存。
  • 库存扣减需保证原子性,避免超卖。

解决方案

  1. 库存缓存
    // Redis 存储库存(原子操作)
    String key = "seckill:stock:" + itemId;
    Long stock = redisTemplate.opsForValue().decrement(key);
    if (stock < 0) {redisTemplate.opsForValue().increment(key); // 回滚throw new SoldOutException();
    }
    
  2. 本地缓存兜底
    // Caffeine 缓存库存状态(减少Redis压力)
    LoadingCache<String, Boolean> stockCache = Caffeine.newBuilder().expireAfterWrite(100, TimeUnit.MILLISECONDS).build(k -> redisTemplate.hasKey(k));public boolean isItemAvailable(String itemId) {return stockCache.get("seckill:stock:" + itemId);
    }
    
  3. 异步扣减数据库
    @Async
    public void asyncReduceStock(String itemId) {itemDao.reduceStock(itemId); // 最终一致性
    }
    

案例12:社交媒体热点新闻缓存

挑战

  • 突发流量导致热点新闻 DB 查询激增。
  • 缓存击穿风险高。

解决方案

  1. 动态热点探测
    // 使用 Redis HyperLogLog 统计访问量
    public void trackNewsAccess(String newsId) {String key = "news:access:" + newsId;redisTemplate.opsForHyperLogLog().add  

八、分布式缓存在微服务中的实战应用

1. 微服务架构下的缓存设计挑战

在微服务架构中,服务拆分导致数据分散,缓存设计需解决以下问题:

  • 数据一致性:跨服务数据如何同步?
  • 缓存穿透:服务间调用频繁,如何避免重复查询?
  • 热点数据治理:多服务共享数据如何高效缓存?

案例13:订单服务与库存服务的缓存协同
场景:用户下单时需实时检查库存,库存服务独立部署。
解决方案

  1. 本地缓存 + 分布式缓存
    // 订单服务本地缓存库存状态(短期有效)
    @Cacheable(value = "inventoryCache", key = "#itemId")
    public boolean checkInventory(String itemId) {return inventoryServiceClient.getStock(itemId) > 0;
    }// 库存服务更新时发布事件
    @PostMapping("/updateStock")
    public void updateStock(@RequestBody StockUpdateRequest request) {inventoryDao.update(request);kafkaTemplate.send("inventory-update", request.getItemId());
    }// 订单服务监听库存变更
    @KafkaListener(topics = "inventory-update")
    public void evictCache(String itemId) {cacheManager.getCache("inventoryCache").evict(itemId);
    }
    
  2. 效果
    • 减少 80% 的库存服务调用。
    • 库存变更后 1 秒内缓存失效,保证准实时一致性。

九、缓存与消息队列的深度集成

1. 异步更新缓存的最终一致性

案例14:用户资料更新同步
需求:用户修改头像后,所有服务缓存需更新。
方案

// 用户服务更新DB并发送事件
public void updateAvatar(String userId, String avatarUrl) {userDao.updateAvatar(userId, avatarUrl);kafkaTemplate.send("user-profile-update", new UserEvent(userId, "AVATAR_UPDATE", avatarUrl));
}// 其他服务监听事件更新本地缓存
@KafkaListener(topics = "user-profile-update")
public void handleUserEvent(UserEvent event) {if ("AVATAR_UPDATE".equals(event.getType())) {localCache.put("user:" + event.getUserId(), event.getData());redis.delete("user:" + event.getUserId()); // 清理分布式缓存}
}
2. 消息队列削峰填谷

案例15:大促期间订单状态缓存更新
挑战:瞬时 10 万订单创建,DB 写入压力大。
方案

// 订单创建后先写缓存,异步持久化
public void createOrder(Order order) {redisTemplate.opsForValue().set("order:" + order.getId(), order);kafkaTemplate.send("order-create", order);
}// 消费者批量写入DB
@KafkaListener(topics = "order-create", concurrency = "4")
public void batchSaveOrders(List<Order> orders) {orderDao.batchInsert(orders);
}

十、云原生环境下的缓存管理

1. Kubernetes 中的 Redis 集群部署

架构图

┌───────────────────────────────────────┐
│               Kubernetes Cluster      │
│ ┌──────────┐  ┌──────────┐  ┌──────────┐ │
│ │ Redis Pod│  │ Redis Pod│  │ Redis Pod│ │
│ │ (Master) │  │ (Slave)  │  │ (Slave)  │ │
│ └──────────┘  └──────────┘  └──────────┘ │
│ Services: redis-master, redis-replicas   │
└───────────────────────────────────────┘

部署文件片段(Helm Chart)

# values.yaml
architecture: replication
sentinel:enabled: true
master:persistence:size: 50Gi
replica:replicaCount: 3persistence:size: 50Gi
2. 自动扩缩容策略

基于 HPA 的弹性伸缩

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:name: redis-autoscaler
spec:scaleTargetRef:apiVersion: apps/v1kind: StatefulSetname: redis-replicasminReplicas: 3maxReplicas: 10metrics:- type: Resourceresource:name: cputarget:type: UtilizationaverageUtilization: 70

十一、安全与合规性设计

1. 缓存数据加密

场景:缓存用户敏感信息(如手机号)。
方案:客户端加密 + Redis 透明加密(TDE)。

// 写入前加密
public void cacheUserPhone(String userId, String phone) {String encrypted = AES.encrypt(phone, secretKey);redisTemplate.opsForValue().set("user:phone:" + userId, encrypted);
}// 读取后解密
public String getPhone(String userId) {String encrypted = redisTemplate.opsForValue().get("user:phone:" + userId);return AES.decrypt(encrypted, secretKey);
}
2. 访问控制与审计

Redis ACL 配置

# 创建运维账号(只读)
ACL SETUSER opsuser on >ops_password ~* &* +@read# 创建应用账号(限制命令)
ACL SETUSER appuser on >app_password ~cache:* +get +set +del

审计日志

# redis.conf
audit-log enabled
audit-log-file /var/log/redis/audit.log
audit-log-format JSON

十二、全球化架构中的缓存同步

1. 多区域缓存同步策略

在全球化业务场景中,缓存同步需解决 跨区域网络延迟数据一致性容灾切换 三大挑战。以下是针对电商库存同步的完整方案设计:


案例16:全球电商库存同步

需求:北京、法兰克福、北美区域库存数据实时同步,支持以下特性:

  • 强最终一致性:各区域库存扣减后,10 秒内同步至其他区域。
  • 高可用性:单区域故障时,自动切换流量至其他区域。
  • 原子性保障:避免超卖(如北京和北美同时扣减同一商品库存)。

架构设计
                              ┌───────────────────────────┐│         Kafka Global       ││   (跨区域同步Topic)          │└─────────────┬─────────────┘│┌──────────────────────────┼──────────────────────────┐│                          │                          │┌─────▼─────┐              ┌─────▼─────┐              ┌─────▼─────┐│ 北京 Region │              │ 法兰克福 Region│              │ 北美 Region  ││  Redis Cluster◄────Sync────►Redis Cluster◄────Sync────►Redis Cluster ││   + 库存服务  │              │   + 库存服务  │              │   + 库存服务  │└────────────┘              └────────────┘              └────────────┘
核心组件说明
  1. Redis Cluster
    • 每个区域部署独立的 Redis 集群,存储本地库存数据。
    • 启用 active-replica 模式,支持跨区域双向同步。
  2. Kafka Global
    • 全局共享 Topic(如 inventory-update-global),用于跨区域库存变更事件广播。
    • 消息格式包含操作类型(扣减/回滚)、商品ID、数量、区域时间戳。
  3. 库存服务
    • 处理本地库存操作,发布变更事件到 Kafka。
    • 监听其他区域事件,更新本地缓存。

技术实现
2.1 库存扣减与同步流程
// 北京区域库存服务代码示例
public class InventoryService {@Autowiredprivate RedisTemplate<String, Integer> redisTemplate;@Autowiredprivate KafkaTemplate<String, InventoryEvent> kafkaTemplate;/*** 扣减库存(本地优先)*/@Transactionalpublic boolean deductStock(String itemId, int quantity) {// 1. 本地Redis原子扣减Long remaining = redisTemplate.opsForValue().decrement(itemId, quantity);if (remaining < 0) {redisTemplate.opsForValue().increment(itemId, quantity); // 回滚return false;}// 2. 发布库存变更事件到Kafka GlobalInventoryEvent event = new InventoryEvent("deduct", itemId, quantity, System.currentTimeMillis(), "beijing");kafkaTemplate.send("inventory-update-global", event);return true;}/*** 监听其他区域事件*/@KafkaListener(topics = "inventory-update-global")public void handleGlobalEvent(InventoryEvent event) {if ("deduct".equals(event.getType())) {// 3. 异步更新本地Redis(幂等操作)redisTemplate.opsForValue().decrement(event.getItemId(), event.getQuantity());}}
}
2.2 冲突解决策略
  • 向量时钟(Vector Clock)
    每个事件携带区域时间戳,合并时按时间戳最新值生效。
    public class InventoryEvent {private String type;private String itemId;private int quantity;private long timestamp; // 区域时间戳private String region;  // 区域标识// getters/setters
    }
    
  • 冲突检测与修复
    定期扫描库存差异,触发人工或自动校准(如从数据库拉取最终库存)。

优势与挑战
优势挑战解决方案
低延迟本地读写跨区域同步延迟(100-300ms)业务层容忍短暂不一致,最终一致
区域自治,单点故障不影响其他区域网络分区导致数据冲突向量时钟 + 定期校准
支持水平扩展Kafka 全局 Topic 运维复杂度高使用 Confluent Cloud 托管服务

2. 容灾与流量切换

容灾策略

  1. 健康检查:每 5 秒检测区域 Redis 和 Kafka 状态。
  2. DNS 切换:故障时更新全局 DNS,将流量导向最近健康区域。
  3. 数据补偿:故障恢复后,从 Kafka 回溯未同步事件。

流量切换示例(Nginx 配置)

# 根据健康状态路由流量
upstream inventory_servers {zone inventory_zone 64k;server beijing.inventory.com:8080 max_fails=3 fail_timeout=30s;server frankfurt.inventory.com:8080 backup;server na.inventory.com:8080 backup;
}server {location /inventory {proxy_pass http://inventory_servers;health_check interval=5s uri=/health;}
}

3. 监控体系

核心监控指标

指标工具报警阈值
区域间同步延迟Prometheus> 500ms
Kafka 消息积压量Confluent Control Center> 1,000
Redis 内存使用率Grafana + Redis Exporter> 85%
库存差异率自定义脚本> 1% (持续5分钟)

总结

全球化缓存同步需在 性能一致性复杂度 之间权衡:

  • 推荐方案:本地 Redis 集群 + Kafka 全局事件同步 + 向量时钟冲突解决。
  • 典型应用:电商库存、优惠券发放、用户会话管理。
  • 避坑指南
    • 避免跨区域强一致性(CAP 定理限制)。
    • 为同步延迟设计补偿机制(如预留库存缓冲)。
    • 定期演练区域故障切换流程。
http://www.lryc.cn/news/575586.html

相关文章:

  • 光场操控新突破!3D 光学信息处理迎来通用 PSF 工程时代--《自然》子刊:无需复杂算法,这一技术让 3D 光学成像实现 “即拍即得”念日
  • 从零开始的云计算生活——第二十四天,重起航帆,初见MySQL数据库
  • Linux中部署Jenkins保姆间教程
  • 编写CSS的格式
  • React:利用计算属性名特点更新表单值
  • Spring Security 安全控制终极指南
  • ubuntu20.04如何给appImage创建快捷方式
  • 【thinkphp5】Session和Cache记录微信accesstoken
  • 【Docker基础】Docker容器管理:docker rm及其参数详解
  • 百度中年危机:一场艰难的突围战
  • 关于单片机的基础知识(一)
  • 苍穹外卖day3--公共字段填充+新增菜品
  • 【LLM安全】MCP(模型上下文协议)及其关键漏洞、技术细节
  • 解锁企业效率革命:Microsoft 365 Copilot 重塑办公新范式
  • 16.1 Python应用容器化终极指南:Dockerfile多阶段构建与安全优化实战
  • leetcode-2311.小于等于k的最长二进制子序列
  • Apipost和Postman对比
  • view-design的日期时间插件怎么在只选择日期没有选时间的时候给他默认的时间
  • 英特尔汽车业务败走中国,喊出“All in”才过两个月
  • 【机器学习深度学习】线性回归
  • 供应链数据可视化大屏
  • 【Pandas】pandas DataFrame first_valid_index
  • Spring Boot 文件上传大小配置错误解决方案
  • 远程面试平台选声网视频通话提升候选人体验感
  • c++17标准std::filesystem常用函数
  • 微服务架构下面临的安全、合规审计挑战
  • 基于STM32的工业仓库环境智能监控系统设计
  • .NET测试工具Parasoft dotTEST内置安全标准,编码合规更高效
  • Java 大视界 -- 基于 Java 的大数据可视化在智慧城市能源消耗动态监测与优化决策中的应用(324)
  • 单RV的ROI区域算法guess