基于 Cassandra、SolrCloud、Zookeeper、Kafka 和 Python 微服务的搜索系统搭建实践

引言

在现代电商和搜索业务中,常需要构建高性能的搜索平台。本次实践分享介绍如何使用 Cassandra(分布式 NoSQL 数据库)、SolrCloud(分布式搜索引擎)、Zookeeper(分布式协调服务)、Kafka(消息队列)以及 Python 微服务 来搭建一个可扩展的搜索系统。本文以一个实际项目为背景,该项目最初基于 Java/Spring Boot 实现,我们将演示如何改用 Python 微服务模块实现同样的功能。文章涵盖环境准备、各组件安装配置、Python 微服务部署、Cassandra 数据模型设计、Solr 索引配置、集群搭建注意事项等内容,最后总结实践经验和教训。

环境准备与架构概述

在开始搭建之前,需要准备好基础运行环境和硬件资源。本方案假设使用 Linux 服务器(例如 CentOS 或 Ubuntu),并已安装合适版本的 Java JDK(因为 Cassandra、Solr、Kafka 都依赖 Java 运行)。同时,准备多台服务器以搭建集群:

  • Zookeeper 集群:3 台节点,用于协调 Kafka 和 SolrCloud(假定 IP 为 10.201.X.X 三台不同机器,客户端端口 2181)。
  • Kafka 集群:若干节点(假设 3 台或以上),使用上述 Zookeeper 集群进行协调。Kafka 负责接收和传递产品数据更新的消息。
  • Cassandra 节点:1 台或多台(根据数据量和容错需要,可部署为集群),用于存储产品数据,假定单节点 IP 为 10.201.X.X。
  • SolrCloud 集群:3 台 Solr 节点,组成搜索索引集群,每台部署 SolrCloud 实例(假定 IP 分别为 10.201.X.X 三台)。
  • Python 微服务:至少包含两个服务示例:
  • 数据同步服务:消费 Kafka 消息,将新产品数据写入 Cassandra,并更新 Solr 索引。
  • 搜索 API 服务:提供 REST 接口供前端查询,通过 Solr 提供搜索结果(也可直接由前端查询 Solr,但加入微服务可方便做权限控制和聚合)。

各组件通过内部网络通信,确保各端口互通(例如:Cassandra 默认 9042,Solr 8983,Zookeeper 2181,Kafka 9092,微服务根据配置自定端口)。在实际配置中,请将文中出现的 IP、域名、账户密码等替换为您自己环境的实际信息(本文中已使用占位符如 10.201.X.X 进行脱敏处理)。

安装与配置 Cassandra

安装 Cassandra

到 Apache 官方站点下载适用于您操作系统的 Cassandra 二进制发行版(本文以 Cassandra 3.11.12 为例)。将安装包上传到目标服务器 10.201.X.X 并解压,例如:

$ wget https://downloads.apache.org/cassandra/3.11.12/apache-cassandra-3.11.12-bin.tar.gz
$ tar -zxvf apache-cassandra-3.11.12-bin.tar.gz
$ cd apache-cassandra-3.11.12

Cassandra 解压后即可使用,无需额外编译。进入 Cassandra 目录,可以直接通过 bin/cassandra 命令启动节点。第一次启动前,我们需要修改配置文件确保节点通信正常。

配置 Cassandra 节点

打开 conf/cassandra.yaml 配置文件,按照实际网络环境进行调整:

  • cluster_name:集群名称,可自定义。例如 cluster_name: “SearchCluster”。
  • listen_address:监听地址,设置为本机内网 IP,例如:listen_address: 10.201.X.X。
  • rpc_address:RPC 地址(Thrift,仅在使用老客户端时需要)和 native_transport_address(CQL 使用的地址)。可以设置为本机 IP,如:rpc_address: 10.201.X.X (在 Cassandra 3.x 中 rpc_address 控制 CQL 服务绑定)。
  • seed_provider:种子节点列表。如果是单节点测试,可将其设为本机 IP;如是多节点集群,填入初始引导的种子节点 IP 列表。例:
seed_provider:
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          - seeds: "10.201.X.X,10.201.X.X"

确保至少包含集群中的一个节点 IP 作为种子。

  • 其他参数:根据需要调整内存和垃圾回收等设置(默认配置一般可用,生产环境视内存大小调整 -Xmx 等)。

完成配置后,启动 Cassandra 服务:

$ bin/cassandra -R   # 后台启动 Cassandra (-R 可去除超级用户模式限制)

初次启动可能需要等待片刻让 Cassandra 完成初始化。使用自带的 CQL Shell 验证连接:

$ bin/cqlsh 10.201.X.X 9042   # 连接到本机的 Cassandra CQL 服务
Connected to SearchCluster at 10.201.X.X:9042.
cqlsh>

连接成功后,即可创建 Keyspace 和表。例如,创建关键空间 search:

CREATE KEYSPACE search 
WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} 
AND durable_writes = true;

注意: 以上使用了简单策略和副本因子1,适用于测试环境。生产集群应根据机房分布采用 NetworkTopologyStrategy 并设定合适的副本数。

设计 Cassandra 表: 针对搜索系统的需求,我们设计 Cassandra 数据模型来存储商品及相关属性信息。原则上 Cassandra 适合存储宽表结构的数据,每个表以查询需求为导向设计主键。我们在 search keyspace 下建立多张表来分别存储不同类型的信息。例如:

  • 产品主表 (goods):存储商品的主要字段,以商品ID (id)为主键,包含商品名称、描述、主分类等。
  • 属性表 (attr 等):按属性类型拆分成多张表,主键也是商品ID,每张表存储商品的特定属性集合(如规格参数、营销标签等),包含版本号字段用于记录更新版本。
  • 其他维度表 (category 等):根据业务需要建立,例如按类目、品牌、促销等维度组织的数据表,用于支持特定查询或统计。

每个商品在 Cassandra 中会有一系列关联记录。例如商品基本信息在主表一行,属性信息在属性表中一行,等等。这种设计便于通过商品ID快速获取完整信息。由于搜索查询主要由 Solr 执行,Cassandra 的作用是持久化存储和提供数据源,查询时通常并不会直接访问 Cassandra,而是由索引服务预先将数据导入 Solr。

安装与配置 Zookeeper

Zookeeper 在本方案中充当两个角色:Kafka 的协调服务和 SolrCloud 的配置管理。我们搭建一个由 3 台节点组成的 Zookeeper 集群,以保证高可用。

安装 Zookeeper

下载 Zookeeper(二进制发行版),例如使用 3.7.0 版本:

$ wget https://downloads.apache.org/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
$ tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz
$ mv apache-zookeeper-3.7.0-bin /opt/app/zookeeper

在每台 Zookeeper 服务器上都执行上述下载解压。假定三台 ZK 服务器的 IP 分别为 10.201.X.X、10.201.X.X、10.201.X.X。

配置 Zookeeper

在每台节点的 conf 目录下复制一份模板:

$ cp conf/zoo_sample.cfg conf/zoo.cfg

编辑 zoo.cfg,主要关注以下配置:

  • dataDir=/path/to/zookeeper/data:指定数据存储目录,比如 /opt/app/zookeeper/data,确保该目录存在并有读写权限。
  • clientPort=2181:客户端连接端口,默认2181,一般保持不变。
  • 集群相关配置,在文件末尾添加:
server.1=10.201.X.X:2888:3888
server.2=10.201.X.X:2888:3888
server.3=10.201.X.X:2888:3888

这里 server.N 的 N 对应每台服务器的唯一编号。2888 是集群通讯端口,3888 为选举端口。

  • 在每台节点上创建一个名为 myid 的文件放入 dataDir,文件内容为该节点的编号,例如节点1写入1,节点2写入2,节点3写入3。

启动 Zookeeper 集群

在每台服务器上执行:

$ ./bin/zkServer.sh start

启动后,可通过 zkServer.sh status 检查状态,应看到其中一台为 leader,其他为 follower。如果需要验证 ZK 集群可用性,使用 zkCli 连接任意节点:

$ ./bin/zkCli.sh -server 10.201.X.X:2181

可以尝试创建节点测试,如:

[zk: 10.201.X.X:2181(CONNECTED) 0] create /solr_demo "test"

成功创建则说明 ZK 正常工作。我们稍后会在 ZK 上使用路径 /solr_demo 来存储 SolrCloud 的配置数据(即设置一个chroot路径)。

安装与配置 Kafka

安装 Kafka

Kafka 可以在 Kafka 官网或 Apache 存档下载。这里以 Kafka 2.x 为例:

$ wget https://downloads.apache.org/kafka/2.7.0/kafka_2.12-2.7.0.tgz
$ tar -zxvf kafka_2.12-2.7.0.tgz
$ mv kafka_2.12-2.7.0 /opt/app/kafka

在每台 Kafka 服务器上解压安装包。Kafka 也依赖 Java 环境,确保已经安装 JDK 1.8+。

配置 Kafka Broker

编辑 Kafka 的配置文件 config/server.properties:

  • broker.id:集群中每个节点需要唯一的 broker.id(整数)。如第一台设为0,第二台1,第三台2等。
  • listeners 和 advertised.listeners:配置监听地址和对外通告地址。例如单机可用默认 PLAINTEXT://:9092 监听所有网卡。如果有多网卡或 Docker 环境需设置 advertised.listeners 为实际可访问地址,比如 PLAINTEXT://10.201.X.X:9092。
  • zookeeper.connect:设置连接的 Zookeeper 集群地址列表。例如:
zookeeper.connect=10.201.X.X:2181,10.201.X.X:2181,10.201.X.X:2181

如果 SolrCloud 使用了 ZK 的 /solr_demo 子路径,Kafka 可以不使用该子路径,直接连根目录(Kafka 会在 ZK 上创建 /brokers 等路径)。

  • log.dirs:Kafka 存储消息的日志目录,指定一个实际存在的磁盘路径,如 /opt/app/kafka/logs.

根据需要也可调整 Kafka 内存及其他参数,但默认配置适合初始测试。

启动 Kafka

依次在每台 Kafka 节点上启动 broker:

$ ./bin/kafka-server-start.sh -daemon config/server.properties

使用 -daemon 参数可以后台运行。启动后,Kafka 会连接 Zookeeper 注册自己。可以通过 Zookeeper 客户端查看 /brokers/ids 节点下是否有对应的 broker ID 出现。

创建主题 (Topic)

根据业务需要创建 Kafka 主题,用于传递产品数据更新。例如创建一个名为 product_update 的主题,副本因子为2,分区数为3:

$ ./bin/kafka-topics.sh --create --topic product_update --partitions 3 --replication-factor 2 --bootstrap-server 10.201.X.X:9092

(—bootstrap-server 指定任意一个Kafka节点的地址)。确保主题创建成功,可以列出当前主题验证:

$ ./bin/kafka-topics.sh --list --bootstrap-server 10.201.X.X:9092

Kafka 集群至此准备就绪。

安装与配置 SolrCloud

Solr 是构建搜索索引的核心组件。我们使用 SolrCloud 模式 部署,以支持分片和高可用。这里以 Solr 7.7.3 为例。

安装 Solr

从 Solr 官方下载对应版本压缩包(zip 或 tgz),然后在每台 Solr 节点上解压。例如:

$ wget https://archive.apache.org/dist/lucene/solr/7.7.3/solr-7.7.3.tgz
$ tar -zxvf solr-7.7.3.tgz
$ mv solr-7.7.3 /opt/app/solr

准备 SolrCloud 配置

在首次启动 SolrCloud 之前,需要将 Solr 核心配置 上传到 Zookeeper,或者在启动时指定让 Solr自动上传。本项目的 Solr 模块包含一个名为 “product” 的 collection(索引集合)。开发人员已经准备好 Solr 的 schema 配置和 DIH(Data Import Handler)配置。在我们的部署中,采取如下步骤:

  • 配置 ZK_HOST: 编辑 solr-7.7.3/bin/solr.in.sh 文件,找到 ZK_HOST 设置,将其指向我们的 Zookeeper 集群地址和Solr配置的路径。例如:
ZK_HOST="10.201.X.X:2181,10.201.X.X:2181,10.201.X.X:2181/solr_demo"

这里添加了 /solr_demo,意味着 SolrCloud 将在 ZK 上的该路径下存储配置数据。确保该路径已存在(之前通过 zkCli 创建过 /solr_demo 节点)。

  • 集群其他配置: 如果需要,可以在 solr.in.sh 中调整 JVM 内存大小(SOLR_HEAP)以及 GC 策略等。默认情况下 Solr 7 会给出合理的 JVM 参数,我们根据节点内存大小调整,例如设置 SOLR_HEAP=“1g”。

  • DataImportHandler (DIH) 配置: 如果采用 DIH 从 Cassandra 导入数据,需要在 Solr 中加入 DIH 的插件。Solr 7.7.3 已经提供 solr-dataimporthandler jar 包,但默认未包括在 solr-webapp 中。将以下jar复制到 Solr 的 solr-webapp/webapp/WEB-INF/lib/ 目录:

    • dist/solr-dataimporthandler-7.7.3.jar
    • dist/solr-dataimporthandler-extras-7.7.3.jar
    • (如果有自定义的 DIH Handler 插件,例如本项目提供的 solr-support-7.7.0-1.0.jar,也复制到该目录)

这些操作可以在一台机器上完成 Solr 配置准备,然后打包整个 solr 目录供所有节点使用。例如,将配置好的 /opt/app/solr 压缩成 solr.zip,然后传到每台 Solr 服务器解压,以确保配置一致。

上传 Solr 配置并启动 SolrCloud

假设开发提供了 Solr core 的配置文件集合(包含 schema.xml, solrconfig.xml 及 DIH 配置 data-config.xml 等)保存在 /home/netty/solr_core_config/product 目录。将此配置上传到 Zookeeper:

$ cd /opt/app/solr
$ ./bin/solr zk upconfig -z 10.201.X.X:2181,10.201.X.X:2181,10.201.X.X:2181/solr_demo \
    -n product -d /home/netty/solr_core_config/product

以上命令将本地的 product 配置目录上传到 ZK,命名为 config set “product”。(如果需要查看已经存在的 config,可用 downconfig 下载,如 ./bin/solr zk downconfig -n product -d ./downloaded_conf -z …)。

启动 Solr 节点

在每台 Solr 服务器上,以 SolrCloud 模式启动 Solr,并让其加入集群:

$ ./bin/solr start -c -m 1g -z 10.201.X.X:2181,10.201.X.X:2181,10.201.X.X:2181/solr_demo -p 8983 -d /opt/app/solr/solr_data

参数说明:-c 表示以Cloud模式启动,-m 1g设置最大堆1GB,-z指定ZK地址列表和路径,-p 8983指定端口(默认8983),-d /opt/app/solr/solr_data 指定Solr实例的数据目录(这里我们将Solr自带的example/server内容复制到了solr_data以独立配置)。

启动所有 Solr 节点后,它们会自动在Zookeeper上注册并形成一个SolrCloud集群。接下来通过 Solr API 创建集合(collection)。可以使用 bin/solr 脚本创建,也可以通过 Solr Admin UI 执行。使用脚本为例:

$ ./bin/solr create -c product -n product -shards 2 -replicationFactor 2 -p 8983

这将创建名称为 product 的集合,使用我们上传的名为 product 的配置集,设置2个分片,每片2个副本。如果已在 solr.in.sh 设置 ZK_HOST,脚本会在集群上创建collection,并在各节点间分配 cores。成功后,SolrCloud 开始对外提供搜索服务。可以在浏览器访问任何一台 Solr 的管理界面(例如 http://10.201.X.X:8983/solr),查看集群状态、collection 列表等。

注意: SolrCloud 使用 Zookeeper 存储配置和集群状态,务必保证 ZK 集群稳定。在配置和启动 Solr 时,如果 ZK 信息有误(如地址或路径错误),Solr 将无法正常启动。

Python 微服务开发与部署

有了上述数据存储和索引组件后,我们使用 Python 实现微服务来连接它们。原项目中基于 Java/Spring Boot 的模块承担了数据同步、搜索等功能。我们以 Python 重写这些模块,并提供示例说明如何启动和管理。

微服务功能划分

  1. 数据同步服务(Kafka 消费者):持续消费 Kafka product_update 主题消息。每当有商品数据更新消息时,使用 Cassandra 驱动将新数据写入 Cassandra 对应表;然后触发 Solr 索引更新。索引更新可以通过Solr提供的HTTP接口提交增量文档或调用DIH全量导入(取决于实现策略)。在 Python 中,可以使用 kafka-python 或 confluent-kafka 库消费消息,用 DataStax 提供的 cassandra-driver 连接 Cassandra,使用 requests 或 pysolr 调用 Solr 的 API。

  2. 搜索 API 服务:对外提供搜索接口(REST API)。客户端的搜索请求由此服务接收,并转发查询给 SolrCloud,整理结果后返回。可以基于 Flask 或 FastAPI 框架实现。服务内部使用 SolrJ 客户端的替代方案(Python 可使用 pysolr 库)查询 Solr 集群,或直接构造 HTTP 请求查询,并将结果转换为JSON输出。这个服务相当于原 Java 模块中的搜索查询模块,它也可从 Cassandra 获取部分信息做补充。例如查询返回的商品ID列表,再从 Cassandra 查询最新库存等(如果这些信息未在索引中)。

  3. 其他辅助服务:比如文件批量导入服务(相当于 product-upload)或定时任务触发服务(相当于 job-trigger),也都可以用 Python 实现。如果使用调度框架(如 xxl-job)需要兼容,可通过 Python 调用其 HTTP 接口或按照协议实现执行器。这里不展开细节。

微服务代码与启动脚本示例

我们以 FastAPI 构建搜索 API 服务为例,并示范如何编写 Python 启动脚本来管理服务的启动和停止。假设搜索服务代码为 app.py,内容如下(简化示例):

# app.py (FastAPI 简易示例)
from fastapi import FastAPI
import pysolr

solr = pysolr.Solr('http://10.201.X.X:8983/solr/product', timeout=10)  # Solr 地址

app = FastAPI()

@app.get("/search")
def search(q: str):
    # 在 Solr 中查询
    results = solr.search(q)
    # 提取需要的字段返回
    docs = [doc for doc in results]
    return {"query": q, "results": docs}

在实际项目中,可能会有更复杂的查询构造和结果处理,这里从简。接下来编写一个管理脚本 service_control.py,用于启动或停止该 FastAPI 服务。我们使用 subprocess 调用 Uvicorn 来运行 FastAPI 应用,以模拟传统 Shell 脚本中 java -jar … & 的做法:

#!/usr/bin/env python3
# service_control.py
import subprocess, sys, os, signal

APP_COMMAND = ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7220"]

def start():
    """启动服务"""
    # 将输出重定向到日志文件
    logfile = open("service.log", "a")
    # 使用 nohup & 类似效果启动子进程
    process = subprocess.Popen(APP_COMMAND, stdout=logfile, stderr=logfile, preexec_fn=os.setpgrp)
    print(f"Service started with PID {process.pid}")

def stop():
    """停止服务"""
    # 查找运行中的进程(通过端口或命令名)
    try:
        # 利用 pgrep 查找 uvicorn 进程
        result = subprocess.run(["pgrep", "-f", "uvicorn.*7220"], capture_output=True, text=True)
        pids = result.stdout.strip().split()
        if not pids:
            print("Service is not running.")
            return
        for pid in pids:
            os.kill(int(pid), signal.SIGTERM)
        print("Service stopped.")
    except Exception as e:
        print(f"Error stopping service: {e}")

def restart():
    """重启服务"""
    stop()
    start()

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: service_control.py [start|stop|restart]")
        sys.exit(1)
    cmd = sys.argv[1]
    if cmd == "start":
        start()
    elif cmd == "stop":
        stop()
    elif cmd == "restart":
        restart()
    else:
        print("Unknown command:", cmd)

上述脚本模拟了 Java 服务的启动脚本逻辑:

  • 使用 uvicorn 来运行 FastAPI 应用(监听在 7220 端口,模拟原 Java 服务端口)。
  • start() 使用 subprocess.Popen 启动子进程,并将其置于独立进程组以脱离父进程(相当于 nohup)。日志输出定向到 service.log。
  • stop() 使用系统命令 pgrep 查找匹配 uvicorn 和端口号的进程,然后发送 SIGTERM 信号关闭(也可直接用 process.pid 文件记录的方法,或使用更便捷的 psutil 库查找进程)。
  • restart() 则顺序调用 stop 再 start。

将 service_control.py 放在服务器上并赋予可执行权限,就可以通过 ./service_control.py start 来启动 Python 微服务,./service_control.py stop 来停止服务了。对于数据同步服务(Kafka 消费者),可以采用类似方式启动。比如编写一个 consumer.py 脚本启动 Kafka 消费循环,并同样用一个控制脚本管理。注意: 生产环境下建议使用更健壮的方式托管微服务(如 Supervisor、systemd 或容器编排等),此处的脚本仅作为示范。

集群部署注意事项

在将上述所有组件部署完成后,还需关注一些集群搭建的细节和最佳实践:

  • 配置管理与同步: 集群环境配置繁多,建议使用配置管理工具(如 Ansible、Chef)或至少使用脚本确保每台机器配置一致。例如 Solr 的 solr.in.sh、Cassandra 的 cassandra.yaml 等在不同节点上需保持一致的参数应统一修改。对于自定义配置文件(如 Solr schema),确保版本正确上传到 Zookeeper 并在所有 Solr 节点生效。
  • 资源分配: Cassandra、Solr、Kafka 都是对内存和IO较敏感的应用。根据机器规格调整它们的 JVM 内存参数:
    • Cassandra 默认使用一半物理内存作为堆,生产可按数据规模调整但避免过大(以免长 GC 停顿)。
    • Solr 根据索引数据大小设置堆内存,保证能容纳常用查询的工作集。如果使用排序/聚合功能,也要考虑增加堆内存。Solr 索引放置在本地磁盘时,注意磁盘空间充足且IO性能良好。
    • Kafka 对文件系统顺序写较友好,但要确保日志目录有足够空间,同时为 JVM 堆和操作系统页面缓存预留内存。通常 Kafka 本身堆不宜过大(几GB即可),更多依赖操作系统缓存加速磁盘IO。
  • 网络与端口: 在部署多节点集群时,确保防火墙放行必要端口:
    • Cassandra 默认 9042 (CQL), 7000/7001 (集群通信), 7199 (JMX)。
    • Zookeeper 2181 客户端端口,2888/3888 集群内部端口需内网互通。
    • Kafka 9092 (或自定义 listeners 端口)需要消费者/生产者访问;若跨机房或容器环境,配置advertised.listeners为可达地址。
    • Solr 8983 (默认),以及 Solr 内部节点间通信端口。如果 SolrCloud 在防火墙隔离环境,需要开放 Solr 对外查询端口和 Zookeeper 端口。
  • 数据导入与一致性: 首次部署时,需要将已有的商品数据导入 Cassandra 和 Solr。可以通过编写批处理脚本读取原始数据源(如CSV/数据库)写入 Cassandra,然后利用 Solr DIH 全量导入,或直接使用 Solr API 批量索引。从此之后,增量数据走 Kafka -> 消费者服务流程自动更新。要确保 Kafka 消费与 Cassandra 写入、Solr 更新三者的事务一致性:可考虑先写 Cassandra,再写 Solr,如果 Solr 更新失败可以有补偿机制(例如定期全量同步修复)。由于 Cassandra 本身是最终一致性模型,写入成功即算完成,不提供事务回滚,所以应用层要做好失败重试。
  • 监控和日志: 部署完成后,推荐为各组件建立监控:
    • Cassandra 可监控节点延迟、读写吞吐、Compaction 状态等,及时扩容或调整参数。
    • Solr 可监控查询QPS、索引大小、缓存命中率等,通过接口或 JMX 获取指标。
    • Kafka 需监控消息堆积情况(Lag)、消费者组状态、磁盘使用等。
    • Python 微服务应记录关键操作日志(如消费了多少消息、查询耗时多少),并配置守护进程确保异常退出时自动重启。可将微服务注册到 Supervisor 或 systemd 以增强稳定性。
  • 故障演练: 在生产前应测试各部分的容错性。例如停止一个 Cassandra 节点看查询是否受影响(需在应用层考虑一致性级别),停止一个 Solr 节点检查查询是否自动切换到副本,以及Kafka任一 broker 挂掉后消息是否仍可正常发送和消费。一旦验证通过,再正式上线运行。

总结与经验教训

通过上述实践,我们成功搭建了一个基于 Cassandra、SolrCloud、Zookeeper、Kafka 和 Python 微服务的分布式搜索系统。相比传统单体搜索应用,这种架构具有良好的扩展性和解耦性:Cassandra 提供高写入性能和水平扩展能力,SolrCloud 提供强大的搜索索引功能,Kafka 则作为异步解耦的管道,Python 微服务让业务逻辑实现更加灵活高效。

在实施过程中,我们得到以下经验教训:

  • 合理的架构设计:在引入多种组件时,要明确它们各自职责,设计好数据流转路径。比如本案例中采用 Kafka 进行数据同步解耦,如果数据变化频率不高,也可以考虑直接由应用触发 Solr 更新,但引入消息队列使系统更松耦合、可伸缩。
  • 充分的测试验证:集群环境的配置细节繁杂,部署完成后需要反复测试。如曾遇到 Solr 节点无法加入集群,后发现是 ZK 路径配置错误;Kafka 消费延迟过高,追查是因消费者线程处理过慢。通过逐一定位问题并调整(例如修改配置或优化代码逻辑),最终使各部分协调工作。
  • Python 替代 Java 的思考:使用 Python 重构微服务模块,大幅减少了样板代码和编译部署时间,开发效率提升。但是也要注意 Python 在多线程、多进程方面的差异,充分利用异步IO或多进程来发挥硬件性能。如果对性能要求极高的场景,仍需慎重评估使用 Python 的成本(可以考虑关键部分用 Cython 或调用JNI等方式优化)。在我们的实践中,Python 完全能够胜任数据消费和查询API的工作,并且易于维护。
  • 配置与维护:集中管理配置是运维成功的关键。建议将配置文件纳入版本控制,并使用配置管理工具批量部署。对于敏感信息(如密码、密钥),使用加密或配置中心管理。整个系统上线后,要有定期的维护计划,包括 Cassandra 列压缩、Solr 索引优化、Kafka 日志清理等任务,以保证系统长时间稳定运行。

总之,本次搭建与部署实践展示了一套较完整的搜索解决方案。从零开始组建这样一个系统需要跨越多个技术领域的知识,通过一步步安装配置和调优,我们掌握了各组件协同工作的要点。在未来的扩展中,可以考虑将此架构容器化部署于 Kubernetes,实现更加自动化的扩容和运维。希望这些经验对正在构建类似搜索平台的工程师有所帮助。

Ge Yuxu • AI & Engineering

脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实,仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
    • 文中所示任何标识符并不对应实际生产环境中的名称或编号。
    • 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
    • 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。

Data Desensitization Notice: All table names, field names, API endpoints, variable names, IP addresses, and sample data appearing in this article are fictitious and intended solely to illustrate technical concepts and implementation steps. The sample code is not actual company code. The proposed solutions are not complete or actual company solutions but are summarized from the author's memory for technical learning and discussion.
    • Any identifiers shown in the text do not correspond to names or numbers in any actual production environment.
    • Sample SQL, scripts, code, and data are for demonstration purposes only, do not contain real business data, and lack the full context required for direct execution or reproduction.
    • Readers who wish to reference the solutions in this article for actual projects should adapt them to their own business scenarios and data security standards, using configurations that comply with internal naming and access control policies.

版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
    • 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
    • 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。

Copyright Notice: The copyright of this article belongs to the original author. Without prior written permission from the author, no entity or individual may copy, reproduce, excerpt, or use it for commercial purposes in any way.
    • For non-commercial citation or reproduction of this content, attribution must be given, and the integrity of the content must be maintained.
    • The author reserves the right to pursue legal action against any legal disputes arising from the commercial use, alteration, or improper citation of this article's content.

Copyright © 1989–Present Ge Yuxu. All Rights Reserved.