OpenFeign 核心概念与快速上手

核心概念与快速上手 一、⚡ 微服务拆了——然后呢? 你把单体应用拆成了用户服务和订单服务。数据库拆了、代码拆了、团队也拆了。然后订单服务需要查用户信息: // 拆分之前——同一个 JVM,直接调方法 User user = userService.getUserById(userId); // 拆分之后——跨 JVM、跨机器 // 你必须写一堆 HTTP 调用代码 RestTemplate restTemplate = new RestTemplate(); String url = "http://user-service:8081/api/users/" + userId; User user = restTemplate.getForObject(url, User.class); 这段代码有四个问题: 问题 RestTemplate 写法 怎么解决 URL 硬编码 "http://user-service:8081/api/users/" 服务名代替 IP:Port——自动发现 参数拼接繁琐 url + userId 手动拼 声明参数——自动放到 URL 上 返回值无类型保障 getForObject(url, User.class) 手动指定 接口方法声明返回类型——编译器检查 和本地调用差距太大 完全不同的调用方式——学习成本 写法完全和本地方法一样 OpenFeign 解决的就是这个问题——让你调远程服务和调本地方法一样,而且完全不侵入被调方的接口。 二、🧩 OpenFeign 是什么——一句话 OpenFeign 是一个声明式 HTTP 客户端。你只需要写一个 Java 接口 + 注解,Feign 自动帮你生成 HTTP 调用的实现。 ...

十二月 10, 2022 · 4 分钟 · 842 字 · yaomingye

Sentinel 核心概念与快速上手

Sentinel 核心概念 一、⚡ 流量控制——三个让你睡不着的问题 你写了三个微服务——用户服务、订单服务、商品服务。跑得挺稳——直到: 问题 ①:大促的流量是平时的 10 倍——订单服务扛不住了 → 一个服务挂了 → 调用它的服务跟着挂 → 整个系统雪崩 → 你想给订单接口限流——每秒最多处理 1000 个请求——多的直接拒绝 问题 ②:商品服务的"查价格"接口突然变慢了——耗时从 50ms 涨到 5s → 调它的线程全在等响应——线程池满了 → 你想检测到 RT 异常时——先熔断掉这个接口——让它别拖死整个系统 问题 ③:不同的调用方重要程度不一样 → 订单支付的接口 > 浏览订单的接口 → 你想在流量高峰时——优先保证支付接口不被限流 这三个问题对应了 Sentinel 的三个核心能力:限流(Flow Control)、熔断降级(Circuit Breaking)、系统自适应保护(System Protection)。 二、🤔 Sentinel 是什么——以及为什么不是 Hystrix Sentinel 是阿里巴巴开源的“流量防卫兵”——它以流量为切入点,从流量控制、熔断降级、系统负载保护三个维度保护服务的稳定性。 Hystrix 和 Sentinel 对比: 维度 Hystrix Sentinel 维护状态 停止维护——只修 Bug 不加新功能 ✅ 活跃维护——阿里巴巴 + 社区 隔离策略 信号量 + 线程池——二选一 信号量(默认)——更轻量 限流粒度 接口级别——比较粗糙 ✅ 可按 QPS/线程/调用方/链路——精细化 熔断策略 按异常比例 ✅ 按慢调用比例 + 异常比例 + 异常数 规则动态修改 需要改代码——不够灵活 ✅ Dashboard 实时改——不需要重启 系统自适应 不支持 ✅ 根据 Load/CPU/RT 自动限流 规则持久化 Archaius(不推荐) ✅ 推/拉模式——Nacos/Apollo/ZK 等 Hystrix 停更后——Sentinel 和 Resilience4j 是两大替代。Resilience4j 更"云原生"(轻量、函数式),Sentinel 更"企业级"(Dashboard 控制台、丰富的规则面板)。如果你的团队用了 Spring Cloud Alibaba——Sentinel 是默认选择。 ...

十二月 6, 2022 · 4 分钟 · 756 字 · yaomingye

Spring Cloud Gateway 核心概念与快速上手

搞懂网关三要素:Route、Predicate、Filter 一、⚡ 微服务上线后——前端疯了 你有 3 个微服务——用户服务在 8081、订单服务在 8082、商品服务在 8083。后端调得挺好——gRPC/Dubbo/REST 各种 RPC 全上了。 然后前端来找你:“我要调三个不同的端口?那用户登录后 Token 怎么统一校验?跨域怎么配?万一商品服务挂了——我是直接给用户看 500 错误还是给个降级提示?" 这些问题都不是前端该解决的——它们应该在一个统一的入口网关里处理: 没有网关: 浏览器 → 直接调 8081(用户服务) 浏览器 → 直接调 8082(订单服务) 浏览器 → 直接调 8083(商品服务) → 三个端口、三次鉴权、三次跨域——前端疯了 有了网关: 浏览器 → 网关 :8080 → /api/users/** 转给 8081 → /api/orders/** 转给 8082 → /api/products/** 转给 8083 → 一个端口、一次鉴权、一处跨域——前端只认识网关 API 网关就是系统的"大门”——所有外部请求都从这一个门进来,由它统一做鉴权、限流、路由、日志、降级。后端服务只关心业务逻辑——不管安全和流量控制。 二、🤔 选型:为什么是 Spring Cloud Gateway? Java 生态中做网关有一堆选择——先搞清楚 Spring Cloud Gateway 在其中的位置: 网关 底层 编程模型 适用场景 Spring Cloud Gateway WebFlux + Netty 响应式——非阻塞 I/O Spring 微服务体系——首选 Zuul 1.x Tomcat + Servlet 阻塞——一个请求一个线程 已停止维护——不推荐新项目 Zuul 2.x Netty 异步——但生态不成熟 几乎没人用 Nginx + Lua (OpenResty) Nginx C 内核 同步——Lua 脚本 性能极高——但开发门槛高 Kong OpenResty Lua + 插件 API 管理平台——适合需要 API 管理的场景 Spring Cloud Gateway 碾压 Zuul 1.x 的根本原因是"非阻塞": ...

十二月 2, 2022 · 5 分钟 · 1008 字 · yaomingye

Dubbo 核心架构与 RPC 模型

Dubbo 核心架构 📖 前置阅读:本文假设读者理解基本的网络通信概念(TCP/IP、HTTP、序列化)。不需要预先了解 RPC——本文从零讲起。 一、⚡ 问题切入:HTTP REST 调用有什么"不够用"的? 互联网公司典型的微服务架构中,服务间通信最常见的方式是 HTTP REST: 订单服务 (OrderService) → 商品服务 (ProductService) GET /api/products/10001 → 返回 JSON {"id": 10001, "name": "iPhone", "stock": 50} POST /api/orders → 返回 JSON {"orderId": 20001, "status": "created"} 这套方案在服务数量少、调用量低时完全够用。但当公司扩张到几十个微服务、每秒上万次调用时,REST 的短板就暴露了: 痛点 REST 的具体表现 连接开销 每次请求都需要建 TCP 连接(HTTP/1.1 支持复用但仍是短连接语义)——高并发时 CPU 和内存吃紧 序列化冗余 JSON 文本格式——字段名重复传输,体量大、解析慢。对比二进制序列化,JSON 的带宽占用高出 3~10 倍 弱类型契约 没有强类型接口定义——调用方靠"文档"或"口头约定"知道参数和返回值类型。商品服务改了字段名,订单服务的代码编译通过、运行时崩 路由单一 URL 路由——无法按业务特性做灰度发布、权重分配、同机房优先路由 缺乏治理 没有内置的负载均衡、熔断、限流——需要额外引入 Spring Cloud、Sentinel 等组件 这时候再看 Dubbo 的设计思路——不是把 HTTP 做得更好,而是用另一套协议和模型来替代 HTTP: ...

十一月 19, 2022 · 6 分钟 · 1089 字 · yaomingye

Kafka 核心架构与日志存储模型

Kafka:分布式提交日志,不是消息队列 📖 前置阅读:本文假设读者已理解消息队列的基本价值(异步、解耦、削峰填谷),最好读过 RabbitMQ 或 RocketMQ 的任意一篇基础文章。有了 MQ 概念再学 Kafka 事半功倍。 一、⚡ 问题切入:RabbitMQ 和 RocketMQ 有什么共同的"毛病"? 先回顾 RabbitMQ 和 RocketMQ 的消费模型: RabbitMQ: Consumer 收到消息 → 手动 basicAck → Broker 删除消息 RocketMQ: Consumer 收到消息 → 返回 CONSUME_SUCCESS → offset 推进 共同点:消息被消费者确认(ACK)后,Broker 就把它删了。消息在 Broker 上的生命周期是"暂存"——它存在只是为了等待消费者拿走。 这个模型有一个隐含的限制:一条消息只能被消费一次。想重放消息?RabbitMQ 做不到(消息已经删了),RocketMQ 可以重置 offset 但受 CommitLog 保留时间限制。 这时候再看 Kafka 的设计:消息消费后不删除。消息存在磁盘上,按时间或大小策略统一过期,消费者想从哪个位置读就从哪个位置读。 Kafka: Consumer 自己管 offset,随时可以回到过去的某个位置重读 消息不是被消费掉的——是按时间自然过期的 这就是 Kafka 和 RabbitMQ/RocketMQ 本质上的不同——Kafka 不是一个消息队列,它是一个分布式提交日志(Distributed Commit Log)。 二、🧬 Kafka 是什么:分布式提交日志 2.1 核心定义 Kafka 的官方定位:分布式、分区化、多副本的提交日志服务。 ...

十一月 13, 2022 · 5 分钟 · 1020 字 · yaomingye

RocketMQ 核心架构与消息模型——领域模型、存储引擎与消息生命周期全景

领域模型与存储引擎 📖 前置阅读:本文假设读者已理解消息队列的基本价值(异步、解耦、削峰填谷)。如果还不熟悉消息队列,建议先阅读 RabbitMQ 核心概念与 AMQP 协议。 一、问题切入:为什么 RocketMQ 的概念比 RabbitMQ 多? RabbitMQ 学完六篇,Exchange / Binding / Queue 的路由模型印象深刻——概念不多,全靠灵活组合。翻开 RocketMQ 的文档,一眼扫过去:Producer、Consumer、Topic、Queue、ConsumerGroup、Subscription、Broker、NameServer……光领域概念就七个,外加两个部署组件。 这不是设计过度,而是 RocketMQ 把"谁负责发、谁负责收、怎么分组、怎么扩容、消息存哪里、谁管路由"全部显式拆开了。 RabbitMQ 用少数概念的组合来表达这些维度,RocketMQ 选择每件事都定义一个独立概念。 好处是每个概念职责单一,坏处是初学者一看就晕——概念之间谁包谁、谁管谁、谁和谁是平等的,不看图根本理不清。 所以这篇不讲"先记住七个概念"——先看一张全景图,把七者的层级关系钉在脑子里。 二、领域模型全景:一张图串起七个概念 Apache RocketMQ 官方把领域模型定义为七个核心概念。这是一张按层级包含关系组织的全景图: flowchart TD subgraph PRODUCTION["① 生产"] P(["Producer\n生产者"]) end subgraph STORAGE["② 存储"] MSG["Message\n消息体"] TOPIC["Topic\n主题(逻辑容器)"] Q0[("Queue-0\n物理分片")] Q1[("Queue-1")] Q2[("Queue-n")] MSG --> TOPIC TOPIC --> Q0 TOPIC --> Q1 TOPIC --> Q2 end subgraph CONSUMPTION["③ 消费"] CG["ConsumerGroup\n消费分组"] C1(["Consumer-1"]) C2(["Consumer-2"]) SUB["Subscription\n订阅关系"] CG --> C1 CG --> C2 CG --> SUB end P -->|"发送"| TOPIC Q0 & Q1 & Q2 -->|"拉取"| CG SUB -.->|"绑定"| TOPIC classDef startEnd fill:#fff5f5,stroke:#e53e3e,stroke-width:2.5px,font-weight:bold; classDef process fill:#f7fafc,stroke:#718096,stroke-width:2px; classDef data fill:#f0fff4,stroke:#38a169,stroke-width:2px,font-weight:bold; classDef root fill:#ebf8ff,stroke:#3182ce,stroke-width:2.5px,font-weight:bold; class P,C1,C2 startEnd; class MSG,TOPIC process; class Q0,Q1,Q2 data; class CG,SUB root; 这张图的阅读顺序:从左到右,消息从 Producer 出发 → 经过 Topic → 落入 Queue → 被 ConsumerGroup 内的 Consumer 拉取。关键层级关系: ...

十一月 7, 2022 · 9 分钟 · 1741 字 · yaomingye

RabbitMQ 核心概念与 AMQP 协议

核心概念与 AMQP 协议 一、⚡ 问题切入:同步处理为什么不行? 先看一个电商系统里最常见的下单流程: @Service public class OrderService { @Transactional public Order createOrder(CreateOrderRequest request) { // 1. 扣减库存 inventoryService.deduct(request.getProductId(), request.getQuantity()); // 2. 创建订单 Order order = orderMapper.insert(request); // 3. 发送下单成功短信——这一步是同步的 smsService.sendOrderConfirm(request.getUserId(), order.getId()); // 4. 发送下单成功邮件——这一步也是同步的 emailService.sendOrderConfirm(request.getUserId(), order.getId()); // 5. 写入操作日志 operationLogService.record("CREATE_ORDER", order.getId()); return order; } } 一次下单请求,用户要等库存扣减、订单入库、短信发送、邮件发送、日志写入全部完成才能收到响应。短信调用运营商接口,邮件走 SMTP,日志写入数据库——这三步加起来可能要 500ms ~ 2s。用户在前端点完"提交订单"后盯着屏幕转圈,体验糟糕。 有人会说:“那简单,开个线程异步执行不就行了?” // 线程池异步——似乎解决了问题 executorService.submit(() -> smsService.sendOrderConfirm(userId, orderId)); executorService.submit(() -> emailService.sendOrderConfirm(userId, orderId)); 但这引入了一连串新问题: ...

十一月 1, 2022 · 7 分钟 · 1466 字 · yaomingye

MongoDB 核心概念

MongoDB 核心概念:文档模型、BSON 与查询操作符全解析 一、⚡ 问题切入:MySQL 为什么不适合这个场景? 先看一个典型的系统设计需求。你正在开发一个 SaaS 平台的"用户自定义表单"功能——每个客户可以自己创建表单,定义不同的字段: 客户A:报名表 → 姓名、手机号、紧急联系人姓名、紧急联系人电话、是否过敏(是/否) 客户B:问卷表 → 昵称、年龄、兴趣爱好(多选)、详细简历(文本)、作品链接 客户C:订单表 → 商品名、单价、数量、收货地址(省/市/区/详细)、发票抬头、纳税人识别号 用 MySQL 做这件事,摆在面前的有三条路: 方案一:一张宽表 CREATE TABLE form_data ( id BIGINT PRIMARY KEY, field_1 VARCHAR(200), -- 姓名/昵称/商品名 field_2 VARCHAR(200), -- 手机号/年龄/单价 field_3 VARCHAR(200), -- 紧急联系人/兴趣爱好/数量 -- ... 预留 50 个字段 field_50 VARCHAR(200) ); 客户A的"紧急联系人电话"存在 field_4,客户B的"作品链接"存在 field_5,客户C的"纳税人识别号"存在 field_7。字段名没有任何业务含义,查询时只能对着文档翻"field_4 到底存了什么"。SQL 写成: SELECT * FROM form_data WHERE field_1 = '张三' AND field_2 = '13800000000'; 这已经不是在写代码了,是在玩解谜游戏。 ...

十月 26, 2022 · 8 分钟 · 1575 字 · yaomingye

Elasticsearch 核心概念

Elasticsearch 核心概念:倒排索引、分词器与 REST API 全解析 一、⚡ 问题切入:MySQL 模糊搜索为什么不行? 先看一个日常开发中最常见的搜索场景。用户在电商平台的搜索框里输入"华为手机",后端需要从商品表中查出匹配的商品。你第一反应肯定是写这样一条 SQL: SELECT * FROM product WHERE name LIKE '%华为手机%'; 这看起来没问题。但产品经理走过来跟你说:“搜索结果要把完全匹配的放在最前面,然后按销量排序,还要展示分类筛选和品牌聚合。“你看着手里的 SQL,表情逐渐僵硬。 MySQL LIKE '%keyword%' 有一个致命伤:前置通配符导致索引失效。B+Tree 索引遵循最左前缀匹配原则,% 一上来就破坏了索引的有序性,数据库只能全表扫描。500 万商品数据,一条 LIKE 查询耗时 3 秒以上——用户体验直接爆炸。 这不是加个索引能解决的问题。MySQL 是为精确匹配和范围查询设计的,不是为人类自然语言的模糊搜索设计的。用户不会输入精确的字段值,他们会打错字(“苹果手鸡”),用近义词(“笔记本” vs “笔记本电脑”),甚至用拼音(“huawei shouji”)。 全文搜索引擎就是为这个问题而生的。看一组实际数据: # MySQL LIKE:2.8 秒(500 万数据) mysql> SELECT * FROM product WHERE name LIKE '%华为手机%'; 500 rows in set (2.812 sec) # Elasticsearch match:0.015 秒(同量级数据,3 节点集群) GET /product/_search { "query": { "match": { "name": "华为手机" } } } # 返回:500 条结果,耗时 15ms,按相关性排序 接近 200 倍 的延迟差距。而且 ES 返回的结果自带相关性评分——包含"华为手机"这四个字且连在一起出现的商品分数最高,只包含"手机"的排在后面,只包含"华为"的更靠后。这就是 ES 作为搜索引擎存在的核心价值。 ...

十月 22, 2022 · 10 分钟 · 2065 字 · yaomingye

Redis 核心架构

Redis 核心架构:五大数据结构与常用命令全解析 一、⚡ 问题切入:MySQL 为什么不够? 先看一个典型的电商场景。商品详情页的 QPS(每秒请求数)在促销期间达到 5000,每个请求需要执行以下 SQL: -- 商品基本信息 SELECT * FROM product WHERE id = 10001; -- 商品 SKU 列表 SELECT * FROM product_sku WHERE product_id = 10001; -- 商品评价统计 SELECT COUNT(*), AVG(rating) FROM review WHERE product_id = 10001; MySQL 单机在简单查询下约能支撑 2000 ~ 3000 QPS,5000 QPS 直接打到数据库会导致连接池耗尽、响应超时,最终服务雪崩。 有人会说"加读写分离、分库分表",但这些方案在数据到达 MySQL 之前就有一个更直接的思路: 把热点数据放在内存里 。 这就是 Redis 存在的根本原因——将频繁访问的数据从磁盘(MySQL)迁移到内存,用空间换时间。一条 Redis GET 命令的延迟通常在 0.1ms 以内,而 MySQL 单条查询即使在索引命中、Buffer Pool 热数据全缓存的情况下,延迟也在 1ms ~ 5ms 之间。差距来自 存储介质 (内存 vs 磁盘)和 数据访问路径 (直接内存寻址 vs B+Tree 遍历)。 ...

十月 19, 2022 · 13 分钟 · 2659 字 · yaomingye
Cat Radio