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

自动化测试(十二) 分布式系统测试-缓存-注册中心与链路追踪验证

分布式系统测试缓存、注册中心与链路追踪验证上篇咱们搞定了消息队列测试今天继续深入分布式系统的其他组件——Redis缓存、服务注册中心、分布式链路追踪。这些基础设施的测试往往被忽略但出了问题定位起来最头疼。一、Redis 缓存测试缓存测试的核心问题缓存命中、缓存穿透、缓存雪崩、数据一致性。场景订单详情缓存ServicepublicclassOrderQueryService{AutowiredprivateOrderRepositoryorderRepository;AutowiredprivateStringRedisTemplateredisTemplate;privatestaticfinalStringORDER_CACHE_KEYorder:%s;privatestaticfinallongCACHE_TTL30;// 30分钟publicOrdergetOrder(LongorderId){StringkeyString.format(ORDER_CACHE_KEY,orderId);// 1. 查缓存StringcachedredisTemplate.opsForValue().get(key);if(cached!null){returnJSON.parseObject(cached,Order.class);}// 2. 查数据库OrderorderorderRepository.findById(orderId).orElseThrow(()-newOrderNotFoundException(orderId));// 3. 写缓存redisTemplate.opsForValue().set(key,JSON.toJSONString(order),CACHE_TTL,TimeUnit.MINUTES);returnorder;}CacheEvict(keyorder: #orderId)publicvoidupdateOrder(LongorderId,OrderUpdateRequestrequest){// 更新数据库...// 缓存由CacheEvict自动删除}}测试方案Testcontainers RedisdependencygroupIdcom.redis.testcontainers/groupIdartifactIdtestcontainers-redis-junit/artifactIdversion2.2.0/versionscopetest/scope/dependencySpringBootTestTestcontainersclassOrderCacheTest{ContainerstaticRedisContainerredisnewRedisContainer(DockerImageName.parse(redis:7-alpine));DynamicPropertySourcestaticvoidconfigureRedis(DynamicPropertyRegistryregistry){registry.add(spring.data.redis.host,redis::getHost);registry.add(spring.data.redis.port,redis::getMappedPort(6379));}AutowiredOrderQueryServicequeryService;AutowiredOrderRepositoryorderRepository;AutowiredStringRedisTemplateredisTemplate;BeforeEachvoidsetUp(){// 清空缓存redisTemplate.getConnectionFactory().getConnection().flushAll();}TestDisplayName(首次查询缓存未命中查数据库并写入缓存)voidshouldQueryDBAndCacheOnFirstAccess(){// Given: 数据库有数据OrderorderorderRepository.save(newOrder(1L,ITEM-001,newBigDecimal(99.99)));// When: 第一次查询OrderresultqueryService.getOrder(order.getId());// Then: 返回正确数据assertThat(result.getId()).isEqualTo(order.getId());// Then: 缓存已写入StringcachedredisTemplate.opsForValue().get(order:order.getId());assertThat(cached).isNotNull();assertThat(cached).contains(ITEM-001);}TestDisplayName(二次查询缓存命中不查数据库)voidshouldHitCacheOnSecondAccess(){// Given: 数据已在缓存OrderorderorderRepository.save(newOrder(1L,ITEM-001,newBigDecimal(99.99)));queryService.getOrder(order.getId());// 预热缓存// When: 再次查询OrderresultqueryService.getOrder(order.getId());// Then: 结果正确虽然没有直接验证没查DB但可以通过监控验证assertThat(result.getSku()).isEqualTo(ITEM-001);}TestDisplayName(更新订单后缓存失效)voidshouldInvalidateCacheOnUpdate(){// Given: 缓存已有数据OrderorderorderRepository.save(newOrder(1L,ITEM-001,newBigDecimal(99.99)));queryService.getOrder(order.getId());// 写缓存// When: 更新订单queryService.updateOrder(order.getId(),newOrderUpdateRequest(ITEM-002));// Then: 缓存已删除StringcachedredisTemplate.opsForValue().get(order:order.getId());assertThat(cached).isNull();}TestDisplayName(缓存过期后重新查数据库)voidshouldQueryDBAfterCacheExpire()throwsInterruptedException{// Given: 写入缓存TTL设短一点方便测试OrderorderorderRepository.save(newOrder(1L,ITEM-001,newBigDecimal(99.99)));queryService.getOrder(order.getId());// When: 等待缓存过期测试中可以把TTL设为1秒Thread.sleep(2000);// Then: 缓存已过期StringcachedredisTemplate.opsForValue().get(order:order.getId());assertThat(cached).isNull();// 再次查询应该重新查DBOrderresultqueryService.getOrder(order.getId());assertThat(result).isNotNull();}}缓存穿透测试TestDisplayName(查询不存在的订单不缓存空值防穿透)voidshouldNotCacheNullResult(){// When: 查询不存在的订单assertThatThrownBy(()-queryService.getOrder(99999L)).isInstanceOf(OrderNotFoundException.class);// Then: 不应该缓存空值否则恶意请求会压垮DBStringcachedredisTemplate.opsForValue().get(order:99999);assertThat(cached).isNull();}TestDisplayName(查询不存在的订单缓存空值布隆过滤器方案)voidshouldCacheNullWithShortTTL(){// 另一种方案缓存空值但TTL很短比如1分钟// 验证空值缓存的TTL}二、服务注册中心测试微服务通过注册中心Nacos/Eureka/Consul互相发现。测试中需要验证服务是否正确注册、是否能被发现、故障时是否剔除。Nacos 测试SpringBootTest(webEnvironmentSpringBootTest.WebEnvironment.RANDOM_PORT)TestcontainersclassServiceDiscoveryTest{ContainerstaticGenericContainer?nacosnewGenericContainer(DockerImageName.parse(nacos/nacos-server:v2.2.3)).withEnv(MODE,standalone).withExposedPorts(8848).waitingFor(Wait.forHttp(/nacos).forStatusCode(200));DynamicPropertySourcestaticvoidconfigureNacos(DynamicPropertyRegistryregistry){StringnacosUrlString.format(http://%s:%d,nacos.getHost(),nacos.getMappedPort(8848));registry.add(spring.cloud.nacos.discovery.server-addr,()-nacosUrl);registry.add(spring.cloud.nacos.config.server-addr,()-nacosUrl);}AutowiredDiscoveryClientdiscoveryClient;TestDisplayName(服务启动后自动注册到Nacos)voidshouldRegisterToNacos(){// 等待注册完成await().atMost(Duration.ofSeconds(30)).pollInterval(Duration.ofSeconds(1)).untilAsserted(()-{ListServiceInstanceinstancesdiscoveryClient.getInstances(order-service);assertThat(instances).isNotEmpty();});}TestDisplayName(能从Nacos发现用户服务)voidshouldDiscoverUserService(){// 先手动注册一个用户服务实例模拟registerMockService(user-service,localhost,8081);// 验证能发现ListServiceInstanceinstancesdiscoveryClient.getInstances(user-service);assertThat(instances).hasSize(1);assertThat(instances.get(0).getHost()).isEqualTo(localhost);}}三、分布式链路追踪测试链路追踪Sleuth Zipkin/Jaeger能帮你追踪请求在多个服务间的流转。测试中需要验证TraceId是否正确传递、Span是否完整、链路数据是否正确上报。场景验证TraceId传递SpringBootTest(webEnvironmentSpringBootTest.WebEnvironment.RANDOM_PORT)classTracingTest{AutowiredTestRestTemplaterestTemplate;AutowiredTracertracer;// Micrometer TracingTestDisplayName(HTTP请求携带TraceId并在服务间传递)voidshouldPropagateTraceId(){// When: 发送请求带自定义TraceIdStringcustomTraceIdabc123;ResponseEntityStringresponserestTemplate.exchange(/api/orders/1,HttpMethod.GET,newHttpEntity(Map.of(X-B3-TraceId,customTraceId)),String.class);// Then: 响应中应该包含Trace信息assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);// 验证日志中包含了TraceId// 可以通过Appender捕获日志验证}TestDisplayName(异步任务继承父Span的TraceId)voidshouldInheritTraceInAsyncTask()throwsException{// Given: 当前有活跃的SpanSpanparentSpantracer.nextSpan().name(parent-operation).start();try(Tracer.SpanInScopewstracer.withSpanInScope(parentSpan)){// When: 提交异步任务CompletableFutureStringfutureCompletableFuture.supplyAsync(()-{// Then: 异步线程中应该能获取到相同的TraceIdSpancurrentSpantracer.currentSpan();assertThat(currentSpan).isNotNull();assertThat(currentSpan.context().traceId()).isEqualTo(parentSpan.context().traceId());returndone;});future.get(5,TimeUnit.SECONDS);}finally{parentSpan.end();}}}Zipkin 验证TestcontainersclassZipkinIntegrationTest{ContainerstaticGenericContainer?zipkinnewGenericContainer(DockerImageName.parse(openzipkin/zipkin:2.24)).withExposedPorts(9411);TestDisplayName(链路数据正确上报到Zipkin)voidshouldReportTracesToZipkin(){// 触发一个跨服务请求orderService.createOrder(request);// 等待数据上报await().atMost(Duration.ofSeconds(10)).untilAsserted(()-{// 查询Zipkin API验证Trace存在StringzipkinUrlString.format(http://%s:%d,zipkin.getHost(),zipkin.getMappedPort(9411));ResponseEntityStringresponserestTemplate.getForEntity(zipkinUrl/api/v2/traces?serviceNameorder-service,String.class);assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);assertThat(response.getBody()).contains(order-service);});}}四、混沌测试入门分布式系统测试的终极形态——故意搞破坏看系统能不能扛住。简单实现随机杀容器TestDisplayName(Redis故障时服务应该降级查数据库)voidshouldFallbackWhenRedisDown(){// Given: 缓存已有数据OrderorderqueryService.getOrder(1L);assertThat(order).isNotNull();// When: 杀掉Redis容器redis.stop();// Then: 服务应该降级查数据库不抛异常OrderfallbackOrderqueryService.getOrder(1L);assertThat(fallbackOrder).isNotNull();assertThat(fallbackOrder.getId()).isEqualTo(1L);// 恢复Redisredis.start();}专业工具Chaos Monkey for Spring BootdependencygroupIdde.codecentric/groupIdartifactIdchaos-monkey-spring-boot/artifactIdversion3.0.2/versionscopetest/scope/dependency# application-chaos.ymlchaos:monkey:enabled:trueassaults:level:3# 攻击强度 1-10latency-active:truelatency-range-start:1000latency-range-end:3000exceptions-active:trueexception:type:java.io.IOExceptionargument:模拟IO异常SpringBootTestActiveProfiles(chaos)classChaosTest{AutowiredOrderServiceorderService;TestDisplayName(在混沌攻击下核心流程仍然可用)voidshouldSurviveChaos(){// 即使服务被注入延迟和异常核心功能应该仍然可用// 验证降级、熔断、重试机制是否生效for(inti0;i10;i){try{OrderResultresultorderService.createOrder(request);// 记录成功/失败}catch(Exceptione){// 验证是预期的异常类型assertThat(e).isInstanceOfAny(ServiceUnavailableException.class,TimeoutException.class);}}}}五、小结今天咱们聊了分布式系统的测试组件测试重点工具Redis缓存命中/穿透/雪崩/一致性Testcontainers Redis注册中心服务注册/发现/剔除Testcontainers Nacos链路追踪TraceId传递/Span完整性Micrometer Tracing Zipkin混沌测试故障降级/熔断/恢复Chaos Monkey一句话总结分布式系统的测试不能只验证正常情况缓存穿透、服务故障、网络延迟这些异常场景才是价值所在。Testcontainers让你能在测试中真实模拟这些场景。

相关文章:

自动化测试(十二) 分布式系统测试-缓存-注册中心与链路追踪验证

分布式系统测试:缓存、注册中心与链路追踪验证上篇咱们搞定了消息队列测试,今天继续深入分布式系统的其他组件——Redis缓存、服务注册中心、分布式链路追踪。这些"基础设施"的测试往往被忽略,但出了问题定位起来最头疼。一、Redis…...

iPaaS平台推荐——五款产品能力与适用场景观察

在数字化转型加速推进的当下,iPaaS(集成平台即服务)正成为企业打通数据孤岛、连接应用生态的核心基础设施。面对市场上类型各异的集成平台,如何根据自身需求选择合适的解决方案,成为众多企业关注的重点。本文基于公开资…...

oh-my-iflow:基于多智能体协作的自动化命令行开发工作流

1. 项目概述:当命令行遇上多智能体工作流如果你和我一样,每天有大量时间泡在终端里,那你肯定对命令行工具的效率又爱又恨。爱的是它直接、强大,恨的是很多复杂任务依然需要我们手动串联多个命令,或者在不同工具间来回切…...

Perplexity Nature检索实战手册:9类典型查询失败场景+对应Prompt工程模板(含IEEE/ACS/Nature交叉验证结果)

更多请点击: https://intelliparadigm.com 第一章:Perplexity Nature文章检索实战手册导论 Perplexity Nature 是面向科研人员与技术从业者设计的智能学术检索增强工具,它融合了语义理解、引用图谱分析与跨源文献聚合能力,专为高…...

ARM MPMC内存控制器架构与优化策略

1. ARM MPMC内存控制器架构解析在嵌入式系统设计中,内存控制器作为处理器与存储设备之间的桥梁,其性能直接影响整个系统的运行效率。ARM PrimeCell多端口内存控制器(MPMC)是一种高度可配置的IP核,支持与多种类型存储设备的连接,包…...

如何构建高效的个人游戏串流服务器:Sunshine完整部署指南

如何构建高效的个人游戏串流服务器:Sunshine完整部署指南 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 在当今数字娱乐时代,游戏玩家面临着设备限制与体验…...

终极NDS游戏资源编辑器Tinke:免费开源工具轻松提取和修改任天堂DS游戏文件

终极NDS游戏资源编辑器Tinke:免费开源工具轻松提取和修改任天堂DS游戏文件 【免费下载链接】tinke Viewer and editor for files of NDS games 项目地址: https://gitcode.com/gh_mirrors/ti/tinke 你是否曾经好奇任天堂DS游戏内部包含了哪些精美的图像、动听…...

移动端数据抓取实战:基于Capacitor插件实现自动化采集

1. 项目概述:一个为移动端设计的“数据抓手”最近在做一个移动端的数据采集项目,需要从一些应用里提取特定的信息。直接写原生代码去解析页面结构,不仅开发周期长,而且一旦目标应用的界面更新,我们的代码就得跟着改&am…...

Claude Code / Cursor 写的代码,你敢直接上线吗?我踩过一次坑,再也不敢

👉 这是一个或许对你有用的社群🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 《项目实战(视频)》:从书中学,往事上…...

5 款实用漏洞扫描工具,网安从业者必备收藏

漏洞扫描是指基于漏洞数据库,通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测,发现可利用漏洞的一种安全检测的行为。 在漏洞扫描过程中,我们经常会借助一些漏扫工具,市面上漏扫工具众多,其中有一…...

基于MCP协议构建AI助手业务工具适配器:从原理到实践

1. 项目概述:用MCP协议为AI助手装上“业务之眼”如果你和我一样,日常开发中需要频繁地在Stripe看支付数据、在Sentry查线上错误、在Notion里翻文档、在Linear跟进任务状态,那你一定懂那种在十几个浏览器标签页和不同SaaS平台间反复横跳的疲惫…...

OpenClaw本地控制台:一站式图形化管理AI助手工作流

1. 项目概述:一个为本地OpenClaw工作流量身打造的控制台如果你和我一样,在Windows上折腾过OpenClaw,那你肯定经历过这种“精神分裂”式的管理体验:想启动服务,得切到终端敲命令;要改个模型配置,…...

构筑数字韧性:从零信任到内生安全,打造面向未来的数字基础设施

1. 从一篇行业评论引发的深度思考:我们该如何构筑数字时代的“安全地基”?前几天,行业媒体EE Times上的一篇旧文被重新翻了出来,标题挺抓人眼球,大致是在讨论某个国家在关键技术领域的主导地位是否面临挑战。抛开其中地…...

为什么93%的DeepSeek PR被拒?揭秘CI流水线自动拦截的4类“伪Clean”代码陷阱

更多请点击: https://intelliparadigm.com 第一章:为什么93%的DeepSeek PR被拒?揭秘CI流水线自动拦截的4类“伪Clean”代码陷阱 DeepSeek 开源仓库的 CI 流水线以严苛著称——最新统计显示,93% 的 PR 在 pre-commit 阶段即被自动…...

OpenClaw Memory启动器:快速构建AI记忆系统的开源脚手架

1. 项目概述:一个为AI记忆系统设计的开源启动器最近在折腾AI应用开发,特别是那些需要长期记忆和上下文管理的项目时,发现了一个挺有意思的GitHub仓库:christiancaviedes/openclaw-memory-starter。这本质上是一个为“OpenClaw Mem…...

从特斯拉事故看自动驾驶数据存储与系统安全设计

1. 事故背景与NTSB调查报告的核心价值2016年发生的那起特斯拉Model S与白色半挂卡车相撞的致命事故,相信很多关注汽车技术发展的朋友都还记得。当时这起事故引发了业界对自动驾驶辅助系统安全性的第一轮大规模公开讨论。一年多后,美国国家运输安全委员会…...

基于MCP协议构建AI知识库:解决会话失忆,实现知识持久化

1. 项目概述:让AI拥有自己的“亚历山大图书馆”如果你和我一样,长期与Claude Code、Cursor这类AI编程助手打交道,一定会遇到一个核心痛点:会话失忆。每次开启一个新对话,AI助手就像一张白纸,它对你项目的历…...

Cursor编辑器AI操作完成音效插件:原理、实现与效能提升

1. 项目概述:一个提升编码体验的“听觉反馈”工具如果你和我一样,每天有大量时间与代码编辑器为伴,那么你一定对那种“沉浸式”的编码状态又爱又恨。爱的是心流状态下的高效产出,恨的是一旦被打断,重新进入状态需要耗费…...

ComfyUI IPAdapter Plus完整指南:5个步骤掌握AI图像风格迁移技术

ComfyUI IPAdapter Plus完整指南:5个步骤掌握AI图像风格迁移技术 【免费下载链接】ComfyUI_IPAdapter_plus 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI_IPAdapter_plus ComfyUI IPAdapter Plus是ComfyUI平台上功能强大的图像引导生成插件&#x…...

AgentVault Memory:构建本地AI编码记忆库,实现跨工具语义搜索与知识管理

1. 项目概述:为什么我们需要一个统一的AI编码记忆库如果你和我一样,每天的工作流里塞满了各种AI编码助手——Claude Code在终端里处理一个项目,Cursor在IDE里开着,偶尔切到OpenCode或者Codex处理点零碎任务。每次对话都充满了宝贵…...

魔兽争霸3优化指南:5个常见问题与WarcraftHelper解决方案

魔兽争霸3优化指南:5个常见问题与WarcraftHelper解决方案 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 你是否在玩《魔兽争霸3》时遇到过…...

macOS Unlocker V3.0:在Windows/Linux电脑上运行macOS虚拟机的终极指南

macOS Unlocker V3.0:在Windows/Linux电脑上运行macOS虚拟机的终极指南 【免费下载链接】unlocker VMware Workstation macOS 项目地址: https://gitcode.com/gh_mirrors/unlo/unlocker macOS Unlocker V3.0是一款革命性的开源工具,专为VMware W…...

芯片设计人才培养:从Sondrel模式看产学合作如何弥合能力鸿沟

1. 项目背景与行业契机最近在整理行业资料时,翻到一篇十多年前的旧闻,讲的是英国一家名为Sondrel的系统级芯片设计咨询公司,与宁波诺丁汉大学合作,启动了一个针对中国学生的芯片设计人才培养项目。这件事发生在2013年,…...

Factool开源框架:构建可信AI的事实核查自动化流水线

1. 项目概述:从“事实核查”到“可信AI”的基石工具在信息爆炸的时代,我们每天都被海量的文本内容包围——新闻稿、分析报告、产品介绍、学术论文,甚至是AI模型自己生成的回答。一个核心的挑战随之而来:如何快速、准确地判断一段文…...

DeepFlow:基于eBPF与Wasm的零代码全栈可观测性平台实战解析

1. 项目概述:从零代码到全栈可观测,DeepFlow 如何重塑云原生与AI应用的监控体验 如果你正在管理一个由微服务、容器和AI模型构成的复杂云原生环境,那么“可观测性”这个词对你来说,可能既熟悉又头疼。熟悉的是,你知道没…...

计算内存(CIM)技术解析与AI硬件加速实践

1. 计算内存(CIM)技术解析:突破传统架构的能效瓶颈 在AI硬件加速领域,计算内存(Compute-in-Memory, CIM)正引发一场架构革命。传统冯诺依曼架构中"内存墙"问题已成为制约AI计算效率的主要瓶颈——…...

Factool:大语言模型事实核查工具包的设计原理与工程实践

1. 项目概述:当AI学会“查证”,我们该如何信任它?最近在折腾大语言模型(LLM)应用落地的朋友,估计都绕不开一个头疼的问题:幻觉(Hallucination)。你让模型写一篇行业报告&…...

联邦学习与RAG融合:构建隐私保护的跨机构智能检索系统

1. 项目概述与核心价值最近在折腾一个跨机构文档智能检索的原型,核心需求是:在不共享原始数据的前提下,让多个参与方(比如几家医院、几个研究实验室)能够联合起来,构建一个强大的、统一的文档知识库&#x…...

【AI工具推荐】Awesome DESIGN.md - 让AI生成像素级完美UI的设计神器

有兴趣的朋友,点点关注。每天分享一个AI工具。每天分享一个AI工具,今天推荐:Awesome DESIGN.md - 一个让AI代理能够生成像素级完美UI的开源设计系统集合项目简介 Awesome DESIGN.md 是一个精心策划的DESIGN.md文件集合,灵感来源于…...

专业级macOS歌词同步方案:LyricsX核心功能深度解析

专业级macOS歌词同步方案:LyricsX核心功能深度解析 【免费下载链接】LyricsX 🎶 Ultimate lyrics app for macOS. 项目地址: https://gitcode.com/gh_mirrors/ly/LyricsX LyricsX是一款专为macOS设计的专业级歌词同步工具,通过智能歌词…...