这部分内容将带您进入构建大型、高并发互联网应用的领域。当单个应用程序(“单体应用”)无法承载海量用户时,我们就需要将其拆分成多个协同工作的服务。而中间件 (Middleware),就是连接这些服务的“高速公路”、“中央邮局”和“超级数据库”,是构建大型系统的必备组件。本课程的所有示例都将在您的Linux系统上进行,我们会介绍如何在Linux环境下与这些中间件进行交互。

第四部分:分布式与微服务

第11章:常用中间件
11.1 缓存技术 (Redis)

1. 核心概念:为什么需要缓存?

想象一下,你的网站有一个非常热门的商品页面,每秒钟都有一千个人在访问。

  • 问题:如果每次访问,你的Java程序都去MySQL数据库里查询一次商品信息,数据库很快就会不堪重负。因为数据库的数据主要存放在硬盘 (Disk)上,硬盘的读写速度相比于内存 (Memory) 要慢成千上万倍。这将成为整个系统的性能瓶颈。

  • 解决方案缓存 (Cache)。我们把这些被频繁访问的“热点”数据,在第一次查询后,就复制一份存放到一个读取速度极快的、基于内存的地方。后续的请求,就直接从这个“高速缓存”里读取数据,而无需再去访问缓慢的数据库。

好比说

  • 数据库:就像一座城市远郊的巨型图书总馆,藏书齐全,但取书(查数据)需要开车往返,很慢。

  • 缓存:就像是在你家楼下的一个小型阅览室,里面只放了最近最火的几十本畅销书。你想看这些书时,下楼就取,速度飞快。

2. 什么是 Redis?

Redis 是目前最流行、性能最高的内存数据库之一。它的所有数据都存放在内存中,这使得它的读写速度快得惊人,非常适合用作缓存。

3. 一步一步在Linux上使用Redis

第一步:安装 Redis 在基于 Debian/Ubuntu 的 Linux 系统上,安装非常简单。

Bash

sudo apt update
sudo apt install redis-server

第二步:启动并测试 Redis 服务 安装后,服务通常会自动启动。我们可以用 Redis 的命令行客户端 redis-cli 来测试一下。

Bash

# 这个命令会向 Redis 服务器发送一个 PING 请求
redis-cli ping

如果服务器回应 PONG,就说明 Redis 已经成功运行了。

第三步:学习基本缓存操作命令

现在,我们来模拟一下缓存“图书”的过程。

Bash

# 进入 Redis 命令行
redis-cli

进入后,你会看到一个 127.0.0.1:6379> 这样的提示符。

  • SET:将数据放入缓存 我们把一本ID为 book:101 的热门书的信息存入缓存。

    SET book:101 "Java编程思想"
    
  • GET:从缓存中读取数据

    GET book:101
    

    服务器会立刻返回 "Java编程思想"

  • EXPIRE:设置过期时间(缓存的核心功能) 缓存里的数据不能永久存在,否则如果数据库里的原数据更新了,缓存里的还是旧数据。我们需要给缓存设置一个“保鲜期”。

    # 设置 book:101 这条缓存的有效期为 60 秒
    EXPIRE book:101 60
    

    60秒后,这条缓存会自动被 Redis 删除。

  • DEL:手动删除缓存

    DEL book:101
    
  • exit: 退出 redis-cli

第四步:理解Java应用中的缓存逻辑

在你的Java代码中,读取数据的逻辑会变成这样:

Java

// 伪代码,演示逻辑
public Book findBookById(String id) {
    // 1. 先去 Redis (高速阅览室) 里找
    Book book = redis.get("book:" + id);

    // 2. 如果找到了 (缓存命中 - Cache Hit)
    if (book != null) {
        System.out.println("从缓存中快速找到了书!");
        return book; // 直接返回,速度极快
    }

    // 3. 如果没找到 (缓存未命中 - Cache Miss)
    else {
        System.out.println("缓存里没有,去数据库总馆慢慢找...");
        // 去慢速的 MySQL 数据库里找
        book = mysql.query("SELECT * FROM books WHERE id = " + id);
        
        // 4. 找到后,放入缓存,并设置过期时间,方便下一个人
        redis.set("book:" + id, book, 60); // 存入缓存,有效期60秒
        
        return book;
    }
}

11.2 消息队列 (Kafka / RocketMQ)

1. 核心概念:为什么需要消息队列?

在一个大型系统中,一个用户的操作可能会触发一系列后续任务。

  • 问题场景(用户下单)

    1. 创建订单记录(快)

    2. 扣减商品库存(快)

    3. 通知仓库发货(可能慢)

    4. 给用户发短信通知(可能慢,且依赖第三方服务)

    5. 为用户增加积分(快)

    如果把这些步骤串行地执行,用户点击“下单”后,需要等待所有步骤都完成才能收到“下单成功”的提示,体验很差。而且,如果第4步发短信的服务恰好坏了,整个下单过程都会失败,这非常不合理。

  • 解决方案消息队列 (Message Queue, 简称MQ)。它是一种用于异步解耦的通信机制。

好比说

  • 没有MQ:你去餐厅吃饭,点完菜后,必须一直在座位上等着服务员去厨房下单、厨师炒菜、再上菜,这个过程你什么也干不了(同步阻塞)。

  • 有了MQ:你去快餐店,在前台点完单(发送消息),拿到一个取餐号(消息ID),然后你就可以自由地去找座位、玩手机(异步非阻塞)。后厨(消费者)会按照订单顺序做餐,做好后会在屏幕上叫你的号。点餐(生产者)和做餐(消费者)两个环节被解耦了。

2. 消息队列带来的三大好处

  • 异步 (Asynchronous):用户无需等待所有耗时操作完成,可以立即得到响应。

  • 解耦 (Decoupling):系统的各个模块之间不直接调用,而是通过消息队列来通信。即使“发短信”服务暂时宕机,也不影响“下单”服务,消息会积压在队列里,等短信服务恢复后再处理。

  • 削峰 (Peak Shaving):在搞促销活动时,瞬间可能有10万个下单请求涌入。如果没有MQ,系统可能会被直接压垮。MQ就像一个巨大的“蓄水池”,能瞬间吸收所有请求,然后让后端的服务按照自己的处理能力,平稳地、慢慢地从池子里取水处理,保证了系统的稳定。

3. 一步一步了解核心组件

  • 第一步:生产者 (Producer)

    • 负责创建和发送消息到消息队列的程序。在我们的例子里,就是“订单服务”。

  • 第二步:消费者 (Consumer)

    • 负责从消息队列中订阅和接收消息并进行处理的程序。在我们的例子里,“仓库服务”和“短信服务”都是消费者。

  • 第三步:消息队列服务 (Broker)

    • 消息队列软件本身,负责接收、存储和转发消息。Kafka和RocketMQ就是两种非常流行的Broker实现。

  • 第四步:主题 (Topic)

    • 消息的分类。生产者将消息发送到指定的主题,消费者订阅自己感兴趣的主题。

    • 例如:一个叫order_created的主题,一个叫user_registered的主题。


11.3 搜索引擎 (Elasticsearch)

1. 核心概念:为什么需要搜索引擎?

  • 问题: 为什么我们不能直接用数据库的 LIKE '%关键词%' 来做搜索?

    1. 性能极差: LIKE '%...%' 无法使用索引,会导致全表扫描,在海量数据下是灾难性的。

    2. 功能有限: 它无法理解“相关性”。搜索“苹果手机”,它搜不出“iPhone”。它也无法实现复杂的筛选、排序和聚合分析。

  • 解决方案: 使用专业的全文搜索引擎,例如 Elasticsearch。

好比说

  • 用数据库LIKE搜索:就像在一座巨大的图书馆里,你想找所有关于“人工智能”的书。你只能一本一本地翻阅每一本书的每一页,效率极低。

  • 用Elasticsearch搜索:就像这座图书馆有一套极其完善的“索引卡片系统”(技术上叫倒排索引)。图书管理员(Elasticsearch)早就把每一本书的内容都打碎成词语,并记录了每个词语出现在哪些书的哪些页码上。当你想找“人工智能”时,管理员只需要去索引卡片里找到“人工智能”这张卡,上面已经清清楚楚地列出了所有相关的书籍和位置,并且按相关度排好了序。

2. 什么是 Elasticsearch (ES)?

Elasticsearch 是一个基于 Lucene 库构建的、分布式的、开源的搜索和分析引擎。它使用 RESTful API 进行交互,非常易用和扩展。

3. 一步一步了解核心概念

  • 第一步:文档 (Document)

    • ES中存储的基本信息单元,相当于数据库中的一数据。它通常是一个JSON对象。

    • 例如:

      JSON

      {
        "productId": 101,
        "productName": "华为 Mate 60 Pro 智能手机",
        "description": "超高速的5G网络体验,强大的拍照功能"
      }
      
  • 第二步:索引 (Index)

    • 一个索引是具有相似特征的文档的集合,相当于数据库中的一张

    • 例如:一个products索引,一个orders索引。

  • 第三步:倒排索引 (Inverted Index)

    • 这是ES实现秒级搜索的核心魔法

    • 传统的索引是“文档 -> 词语”,而倒排索引是“词语 -> 文档列表”。

    • 示例:

      • 文档1: Java is the best language.

      • 文档2: Python is a good language.

      • ES创建的倒排索引 (简化版):

        • "Java": [文档1]

        • "is": [文档1, 文档2]

        • "language": [文档1, 文档2]

        • "best": [文档1]

        • "Python": [文档2]

    • 当你搜索 Java 时,ES只需要瞬间查到这个词,就能立刻知道它在“文档1”中。

4. 一步一步在Linux上与ES交互

ES提供的是HTTP API,我们可以用curl命令来和它对话。

第一步:索引一个文档(写入数据)

Bash

# 向名为 products 的索引中,添加一个ID为1的文档
curl -X PUT "http://localhost:9200/products/_doc/1" -H 'Content-Type: application/json' -d'
{
  "name": "超快跑鞋",
  "description": "专业的马拉松跑步运动鞋"
}'

第二步:搜索文档

Bash

# 在 products 索引中,搜索 description 字段包含 “跑步鞋” 的文档
curl -X GET "http://localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "description": "跑步鞋"
    }
  }
}'
  • 观察现象:即使我们搜索“跑步鞋”,ES也能智能地分析并匹配到包含“跑步运动鞋”的文档,并给出相关性评分。这就是全文搜索引擎的强大之处。

总结:Elasticsearch不仅用于网站和App的搜索功能,它也是ELK (Elasticsearch, Logstash, Kibana) 技术栈的核心,被广泛用于海量日志的实时分析和监控。

个人资料照片

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐