介绍
Quickwit创建分布式集群是比较容易的,我们可以在多个节点上部署Quickwit。如果有Kubernetes环境,官方有提供Helm图表来帮助你在Kubernetes 上部署Quickwit。
本文主要讲解在Docker模式下,通过在部署多个包含Quickwit服务的Docker容器节点,快速实现分布式集群服务;注意:在集群模式下,你必须将索引数据存储在共享存储后端(例如 Amazon S3 或 MinIO、PostgreSQL)上。
官方部署模式文档说明:
Deployment modes | Quickwit

集群结构
采用多节点分布式集群结构
- 采用多节点模式部署,每个节点都支持读写,所有节点将数据索引和元数据统一对接到minio,保证了每一个节点都能写入和查询到索引数据;
- 采用多节点分服务模式部署,所有节点将数据索引和元数据统一对接到minio,写入节点负责将数据流写入到minio索引目录,多个读取节点负责从minio中查询索引数据,每个节点分别专注于读或写,提升节点事务处理效率;
由于资源有限,以下只搭建两个quickwit节点,分别为读(搜索器)和写(索引器);一个基于S3协议的共享存储minio;

说明:
服务名 | 服务 | 说明 |
quickwit1_s3 | Quickwit(可以N个) | 全文搜索引擎(读和写),本例:做为索引器(写) |
quickwit2_s3 | Quickwit(可以N个) | 全文搜索引擎(读和写),本例:做为搜索器(读) |
minio | Minio | 支持s3协议的对象存储服务,存储索引数据块和元数据配置文件 |
Quickwit+S3配置
首先在 Docker服务主机任意目录下创建两个quickwit1_s3_data 和 quickwit2_s3_data文件夹,此文件夹用于安装docker容器时所需的映射卷目录;
mkdir -p quickwit1_s3_data
mkdir -p quickwit2_s3_data

并分别在quickwit1_s3_data 和 quickwit2_s3_data文件夹下创建config文件,用于置放Quickwit的yaml配置文件;
mkdir -p config
从官方github源码工程中下载默认yaml配置文件;
https://github.com/quickwit-oss/quickwit/blob/main/config/quickwit.yaml
将quickwit.yaml分别置放到quickwit1_s3_data/config 和 quickwit2_s3_data/config 文件夹下,后续创建docker容器启动Quickwit服务时,将会加载该yaml配置文件;需置放在docker服务主机物理目录,容器外维护,容器内卷映射;

修改yaml配置文件,添加minio对象存储服务的s3配置,相关配置相参见官方文档:
Storage configuration | Quickwit
# 打开storage.s3注释(需要注意原yaml默认配置注释前为#+空格,去掉#符号后还需要多删一位空格,否则启动服务会提示yaml加载失败,格式错误)
storage:
s3:
flavor: ${QW_S3_FLAVOR} # 默认配置中无此参数,手动添加
access_key_id: ${AWS_ACCESS_KEY_ID} # s3的用户名
secret_access_key: ${AWS_SECRET_ACCESS_KEY} # s3的密码
region: ${AWS_REGION} # 域
endpoint: ${QW_S3_ENDPOINT} #服务地址+端口,http://s3_host:9010
force_path_style_access: ${QW_S3_FORCE_PATH_STYLE_ACCESS:-false} # false
disable_multi_object_delete: false # 是否禁用删除对象数据
disable_multipart_upload: false # 是否禁用上传对象数据
# 添加存储和元数据存储配置s3路径
metastore_uri: s3://${QW_S3_BUCKET}/indexes#polling_interval=30s
default_index_root_uri: s3://${QW_S3_BUCKET}/indexes
打开yaml中的s3注释,修改后如下:

创建Docker容器
使用Portainer平台可以快速方便的拉取docker镜你、创建和维护Docker、支持日志查看、服务启停、进入容器系统等操作,功能非常强大,对于使用和运维Docker环境是非常好用的工具;
本文将在Portainer平台来搭建Quickwit集群和minio服务;
创建MinIO存储
本地已创建包含minio的docker容器服务,只需要在minio上创建一个quickwit存储桶(
Object Browser),本文不在详述minio的容器安装过程,可参见《
Docker安装Minio对象存储》;

在Identity》Users中创建一个新的User账户:
quickwit_s3,输入密码,并分配
redawrite读和写权限,点击save保存;

注意:在保存后弹窗提示复制密钥Key,此密钥Key是访问minio服务的凭证,请自行保管(其它后续我们只需使用账户名和密码);
创建第一个Quickwit写节点
在Portainer》Containers中点击Add containers,进入新增容器配置页面;
Name: quickwit1_s3
Image:quickwit/quickwit:latest
Prot mapping:7281 -> 7280 # (因docker主机上的7280已被使用,更换为7281)

配置
Commands&logging,Commmd中选择Override并输入
run,Entrypoint中选择Override并输入quickwit;

配置Volumes,新增两个Docker服务主机与Docker容器之间的卷目录映射,将容器数据同步到Docker服务主机物理目录上(重要),用于生产数据安全管理;
/quickwit/qwdata和/quickwit/config分为为Docker容器中quickwit搜索引擎服务数据存储目录和配置文件目录,./quickwit1_s3_data为前面在linux系统上提前预建的物理文件夹;
卷目录映射关系为
-v /opt/docker/sysdata/quickwit1_s3_data:/quickwit/qwdata
-v /opt/docker/sysdata/quickwit1_s3_data/config:/quickwit/config
在Volumes中将对应的卷配置设为Bind,如果已创建docker服务主机上的卷目录,也可以使用Voume模式选择可用卷;

在Env中添加Docker容器中服务运行所需的环境变量和参数;

根据前面quickwit.yaml中所配置的s3参数中的规则,添加对应的环境变量,如下:
QW_S3_FLAVOR: minio # 存储类型 minio
QW_S3_ENDPOINT: http://192.168.1.3:9010 # 注意,默认minio端口为9000,因被占用更换成9010
QW_S3_BUCKET: quickwit # minio服务中的存储桶名
AWS_ACCESS_KEY_ID: quickwit_s3 # minio服务的账户名
AWS_SECRET_ACCESS_KEY: quickwit_s3_123456 #inio服务的密码
AWS_REGION:us-east-1 #默认区域
确认各项目配置无误后,点击"Deploy the container" 发布docker容器并启动Quickwit服务;
创建第二个Quickwit读节点
待第二个quickwit集群节点服务,按照上面相同的步骤创建一个相关的docker容器运行节点;
在创建Containers时除了以下配置变更,其它均按第一个quickwit1_s3一样配置;
Name:quickwit2_s3
# 在Volumes中
container:/quickwit/qwdata host:/opt/docker/sysdata/quickwit1_s3_data
container:/quickwit/config host:/opt/docker/sysdata/quickwit1_s3_data/config
所有基于quickwit镜像的docker容器,创建完毕并启动后,在Portainer》Containers中可查看已成功运行的quickwit服务;如服务启动失败,可点击第列表中第一个文件图标查看docker容器运行日志进行排查;

在浏览器中分别访问两个quickwit服务节点UI,进行数据搜索,输入:
http://dcoker_host:7281 和
http://dcoker_host:7282 ;
quickwit1_s3服务节点:
http://192.168.1.3:7281/

quickwit2_s3服务节点:
http://192.168.1.3:7282/

创建Quickwit索引数据
通过采集工具或Java程序上传数据到任意quickwit服务节点中;
以Java程序示例为例
package com.example;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class PullToQuickwitTest {
private static HttpClient httpClient = HttpClient.newHttpClient();
private final static String QUICKWIT_URL = "http://192.168.1.3:7281/";
public static void main(String[] args) throws Exception {
String indexId = "hdfs-logs2";
String jsonData = """
{"timestamp":1739191718,"tenant_id": 1,"app_id": 1111,"body":"foo"}
{"timestamp":1739191758,"tenant_id": 2,"app_id": 1111,"body":"bar"}
{"timestamp":1739191798,"tenant_id": 3,"app_id":"1111","body":"baz"}
""";
String url = "api/v1/" + indexId + "/ingest?commit=force";
System.out.println("请求:" + url);
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(QUICKWIT_URL + url))
.header("Content-Type", "application/json; charset=UTF-8" )
.header("Timeout", "5000")
.POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("状态码:" + response.statusCode());
System.out.println("响应:" + response.body());
}
}
执行无异常后,quickwit服务会返回本次成功提交的数据条数;IDEA控制台打印如下:

在任意一个服务节点上查询已上传到quickwit中的数据;
查看索引数据
我们通过Java程序向quickwit写服务(索引器,端口:7281)上传数据到hdfs-logs2索引后,通过浏览器访问quickwit读服务(搜索器,端口:7282)搜索hdfs-logs2索引数据;如下:

再回到minio控制台页面上,点击查看Object Buckets:quickwit桶,此时indexs索引hdfs-logs2数据块目录已成功创建;

参考: