202410

部分内容由 AI 生成

做一个大型fastapi项目的目录规划

在构建一个大型的 FastAPI 项目时,清晰的目录结构能帮助项目更加可维护、易于扩展,并且利于团队协作。以下是一个典型的目录规划:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
my_fastapi_project/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 的入口文件,创建 app 实例并启动服务
│ ├── core/ # 核心配置模块
│ │ ├── __init__.py
│ │ ├── config.py # 配置项(如数据库URL、环境变量等)
│ │ ├── security.py # 安全相关设置(如加密、鉴权逻辑)
│ │ ├── logging.py # 日志配置
│ ├── api/ # API 路由模块
│ │ ├── __init__.py
│ │ ├── v1/ # API 版本 1
│ │ │ ├── __init__.py
│ │ │ ├── endpoints/ # 各个 API 端点
│ │ │ │ ├── __init__.py
│ │ │ │ ├── users.py # 用户相关接口
│ │ │ │ ├── items.py # 其他模块接口
│ │ │ └── dependencies/ # 依赖项(如权限验证)
│ ├── models/ # 数据库模型
│ │ ├── __init__.py
│ │ ├── user.py # 用户模型
│ │ ├── item.py # 其他模型
│ ├── schemas/ # Pydantic 模式(用于数据验证)
│ │ ├── __init__.py
│ │ ├── user.py # 用户相关数据模式
│ │ ├── item.py # 其他模块的数据模式
│ ├── crud/ # 数据库 CRUD 操作
│ │ ├── __init__.py
│ │ ├── user.py # 用户相关的 CRUD 操作
│ │ ├── item.py # 其他模块的 CRUD 操作
│ ├── db/ # 数据库相关
│ │ ├── __init__.py
│ │ ├── base.py # 数据库基础设置
│ │ ├── session.py # 数据库会话管理
│ │ └── init_db.py # 数据库初始化脚本
│ ├── services/ # 独立业务逻辑模块
│ │ ├── __init__.py
│ │ ├── user_service.py # 用户相关业务逻辑
│ │ ├── email_service.py # 邮件相关逻辑
│ ├── tests/ # 测试用例
│ │ ├── __init__.py
│ │ ├── test_main.py # 主入口测试
│ │ ├── test_user.py # 用户模块测试
│ │ ├── test_item.py # 其他模块测试
├── alembic/ # 数据库迁移目录
│ ├── versions/ # 迁移脚本版本
│ └── alembic.ini # alembic 配置文件
├── scripts/ # 辅助脚本
│ ├── create_superuser.py # 创建超级用户脚本
│ ├── init_data.py # 初始化数据脚本
├── .env # 环境变量配置文件
├── Dockerfile # Docker 镜像配置
├── docker-compose.yml # Docker Compose 配置
├── requirements.txt # Python 依赖包列表
├── README.md # 项目说明文件
└── .gitignore # Git 忽略文件

目录结构说明

  1. app/main.py: 项目入口文件,创建 FastAPI 实例并定义启动流程。
  2. app/core/: 存放核心配置、日志、安全配置等。
  3. app/api/: 各个 API 版本的具体实现,可以通过 v1 等目录区分不同的版本,便于后续扩展。
  4. app/models/: 定义数据库模型。
  5. app/schemas/: 存放 Pydantic 数据验证模型,用于请求和响应数据的结构验证。
  6. app/crud/: 提供数据库 CRUD 操作,封装直接操作数据库的逻辑。
  7. app/db/: 数据库的初始化和会话管理。
  8. app/services/: 存放业务逻辑,与 API 和数据库层解耦。
  9. app/tests/: 包含所有测试用例,可以细分为各个模块的单元测试和集成测试。
  10. alembic/: 数据库迁移工具 Alembic 的配置及版本文件。
  11. scripts/: 包含辅助管理脚本,如创建超级用户或初始化数据的脚本。
  12. Dockerfile & docker-compose.yml: Docker 配置,便于容器化部署。
  13. .env: 存储环境变量,保证敏感信息不直接写入代码。
  14. requirements.txt: 列出项目依赖的第三方包,便于环境一致性。

实现思路

  • 解耦:各层之间使用依赖注入,服务与接口层解耦,使业务逻辑更易于测试和复用。
  • 安全性:将 .envapp/core/config.py 结合使用,通过环境变量管理敏感信息。
  • 模块化:将每个功能模块(如用户、项目等)封装为 CRUD、schema、model、service 等子模块,便于快速定位和调试。

更好的 grep

grep 一个目录下的所有文件,但忽略.git目录和二进制文件

要在一个目录下递归地搜索文本,同时忽略 .git 目录和二进制文件,可以使用以下 grep 命令:

1
grep -rI --exclude-dir='.git' 'search_term' /path/to/directory

参数说明

  • -r: 递归搜索,遍历子目录中的所有文件。
  • -I: 忽略二进制文件。grep 会自动跳过二进制文件,减少干扰。
  • –exclude-dir=‘.git’: 忽略 .git 目录中的内容。你可以添加多个 --exclude-dir 参数来排除多个目录。

示例

假设你想在 /home/user/project 目录中查找包含 TODO 的文件,但忽略 .git 目录和二进制文件:

1
grep -rI --exclude-dir='.git' 'TODO' /home/user/project

这个命令会递归地在 /home/user/project 目录下的所有文件中查找包含 TODO 的文本,跳过 .git 目录和所有二进制文件。

统计每行的逗号

在 Shell 中可以使用 awkgrep 来统计每一行中逗号的个数。以下是几种实现方法:

方法 1:使用 awk

1
awk -F"," '{print NR, ":", NF-1}' filename
  • -F",":指定逗号作为字段分隔符。
  • NF-1NF 表示字段的数量,NF-1 就是逗号的个数。
  • NR:表示当前行号。

输出示例:

1
2
3
1 : 3
2 : 5
...

方法 2:使用 grepsed

1
grep -o "," filename | wc -l

这个命令适合统计文件中所有行的逗号总数,若需要按行统计,则可结合 while 循环:

1
2
3
while IFS= read -r line; do
echo "$line" | grep -o "," | wc -l
done < filename

方法 3:使用 sed

1
sed 's/[^,]//g' filename | awk '{print length}'

这将每一行中非逗号的内容替换为空,然后用 awk 统计字符长度。

tailwind 资源
https://tailadmin.com/

23 Tailwind Dashboards
https://freefrontend.com/tailwind-dashboards/

A free repository for community components using Tailwind CSS
https://www.creative-tim.com/twcomponents

14 Best Free Bootstrap Admin Templates 2024
https://athemes.com/collections/free-bootstrap-admin-templates/

当指定view为flex布局后,给子元素定义width是不起效果的。原因:定义为flex布局元素的子元素,自动获得了flex-shrink的属性,这个属性是什么意思呢?就是告诉子元素当父元素宽度不够用时,自己调整自己所占的宽度比,这个flex-shrink设置为1时,表示所有子元素大家同时缩小来适应总宽度。当flex-shrink设置为0时,表示大家都不缩小适应。所以,倘若给父元素设置了flex布局后,若要其子元素的width有效果,必须给子元素设置flex-shrink为0。

原文链接:https://blog.csdn.net/weixin_51725685/article/details/129310089

Twemproxy 在实际线的使用中,还是存在不少问题的。首先,它是单进程/单线程模型,一个 event_base 要处理所有的事件,这些事件包括 client 请求的读入,转发请求给后端 server,从 server 接受响应,以及将响应发送给 client。单个 Twemproxy 实例,压测最大可以到 8w 左右的 QPS,出于线上稳定性考虑,QPS 最多支撑到 3~4w。而 Memcached 的线上 QPS,一般可以达到 10~20w,一个 Mc 实例前面要挂 3~5 个 Twemproxy 实例。实例数太多,就会引发诸如管理复杂、成本过高等一系列问题。
————————————————
原文链接:https://blog.csdn.net/zhougubei/article/details/139147401

Redis 中有哪些概率性数据结构
https://blog.axiaoxin.com/post/redis-bloom-filter-intro/

概率性数据结构(Probabilistic data structures)是一类用于处理大规模数据集的高效工具,它们通过近似统计结果,如计数、频率和排名等,来替代精确值。虽然这些近似结果并不精确,但它们在许多常见场景中已足够使用,且计算效率更高。此外,这类数据结构还具有其他优势,例如能够模糊化时间、位置等敏感数据。

Redis 常见的概率性数据结构:

  • HyperLogLog:一种用于估算集合基数的概率性数据结构,非常适合用于估算大规模集合的基数,而不需要存储所有元素。
  • Bloom Filter:一种用于检查集合中是否存在某个元素的概率性数据结构,非常适合在大规模数据集中进行快速查询和过滤操作。
  • Cuckoo Filter:一种支持删除操作的概率性数据结构,能够在一定程度上降低误判率,适用于需要更高准确度和支持元素删除的场景。
  • t-digest:一种用于估算数据流中百分位数的概率性数据结构,特别适合处理大规模数据流。
  • Top-K:一种用于找出数据流中最频繁出现项的概率性数据结构,适用于需要实时分析数据流中的热门项的场景。
  • Count-min sketch:一种用于估算数据流中元素频率的概率性数据结构,适用于大规模数据流的频率分析。

选择指南

  • 如果需要快速判断元素是否存在于集合中,并且不需要删除操作,Bloom Filter 是一个极佳的选择。
  • 如果需要检查元素存在性且支持删除操作,Cuckoo Filter 更为适合。
  • 对于估算集合基数,HyperLogLog 是最佳工具。
  • 如果需要实时估算数据流中的百分位数,t-digest 是最佳选择。
  • 若要找出数据流中的最常见元素,Top-K 是最合适的选择。
  • 当需要快速估算数据流中元素的频率时,Count-min Sketch 是理想工具。

从零开始学B端设计
https://www.uxbaike.com/post/5267/5278

https://v2ex.com/t/1088434

  • UI 门槛低,Dribbble 上找现成的设计文件 1:1 抄一抄技术上就没啥问题了,基本的页面组件在 ui8 下个 uikit 看看源文件就行了,两个周就能超过一般所谓的 UI 设计。
  • 移动端的话可以看看 https://m3.material.io/ google 的设计标准

前端工程师如何兼顾设计工作
https://speakerdeck.com/imdonkey01/qian-duan-gong-cheng-shi-ru-he-jian-gu-she-ji-gong-zuo?slide=65

LaTex 简历
https://ppresume.com/pricing

SaaS 产品集成 Stripe 支付的一些坑
https://v2ex.com/t/1073328#reply19

是这样的呢,resume builder 这个市场不算大,但是也不算小,市面上有很多竞品,开源的实现有一个非常优秀的: https://rxresu.me/ 。不过市面上大多数的 resume builder 底层排版引擎是基于 HTML/CSS 实现的,而 HTML/CSS 的精细排版能力比 LaTeX 还是要差一些。PPResume 的核心卖点就是顶级的排版,以及高质量的 PDF 输出,要实现这点,除了了解 LaTeX ,还要了解排版领域的特定知识,比如我写的排版指南: https://docs.ppresume.com/guide/font ,还有很久之前写的一些关于排版工具的一些对比: https://www.douban.com/note/575242910/

Ask HN: Those making $500/month on side projects in 2024 – Show and tell
https://news.ycombinator.com/item?id=39110194

期权策略大全之:日历价差策略
https://baijiahao.baidu.com/s?id=1814653594827597810&wfr=spider&for=pc

欧洲各个人种之间是什么关系?
https://www.163.com/dy/article/FQ8EHURF0543LLR4.html#

mysqldump 导出表和视图的顺序测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mysql> create database mytest1;
Query OK, 1 row affected (0.00 sec)

mysql> use mytest1;
Database changed
mysql> create table t1(id int);
Query OK, 0 rows affected (0.13 sec)

mysql> create table v1 as select * from t1;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

$ mysqldump -udebian-sys-maint mytest1 -p | grep -Ev '\*|--|^$'
Enter password:
DROP TABLE IF EXISTS `t1`;
CREATE TABLE `t1` (
`id` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
LOCK TABLES `t1` WRITE;
UNLOCK TABLES;
DROP TABLE IF EXISTS `v1`;
CREATE TABLE `v1` (
`id` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
LOCK TABLES `v1` WRITE;
UNLOCK TABLES;

新概念英语
http://www.newconceptenglish.com/index.php

linux 数据恢复

sudo fsck /dev/nvme0n1p1
sudo dd if=/dev/sdXn of=/mnt/recovery/backup.img bs=4M
sudo tune2fs -l /dev/nvme0n1p1


sudo ddrescue /dev/nvme0n1p1 /data/temp/dd_image.img /data/temp/dd_logfile.log
sudo losetup --find --show /data/temp/dd_image.img
sudo extundelete /dev/loop12 --restore-file /home/ubuntu/haohu/config.ini
sudo e2fsck -f /dev/loop12
sudo losetup -d /dev/loop12


sudo photorec dd_image.img
$ find . -name '*.ini' | xargs grep smtp
./recup_dir.4/f15986480.ini:[smtp]
$ cat ./recup_dir.4/f15986480.ini
[smtp]
user=onlytiancai@gmail.com

mysqlimport 导入数据时遇到一些问题,如何解决?

  1. 如果 csv 是 gz 压缩格式,没法直接导,解压的话太占磁盘空间。
  2. csv 的文件名必须得和表名一致,导入前必须得给文件改名。
  3. 导入过程中看不到进度。
  4. 如果 csv 中有的列我不想导入,没法过滤。

解决办法:

  1. 可以用 zcat 流式解压 gz 通过管道把数据传递给 mysql 命令,中间不需要占用磁盘。
  2. mysqldump 会根据文件名自动推导表名,所以可以直接用 mysql -e 执行 LOAD DATA LOCAL INFILE
  3. 可以用 pv file.gz | gunzip 代替 zcat 来查看进度。
  4. 管道中可以加入 csvcut 来过滤掉不需要的列。

整个命令看起来如下,执行之前确保服务器执行了 set global local_infile = 1;

1
2
3
4
5
6
pv /data/mydata.csv.gz | gunzip | csvcut -c 1,2,3 |mysql --local-infile -h192.168.1.1 -uuser -p -D mydb -e "
LOAD DATA LOCAL INFILE '/dev/stdin'
INTO TABLE mytable
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '\"'
LINES TERMINATED BY '\n';"

split

split --additional-suffix=.csv -d --numeric-suffixes=0 --suffix-length=3 -l 200000 mydata.csv mydata_

远程写入文件

mysqlbackup --defaults-file=~/my_backup.cnf --backup-image=- --backup-dir=/tmp backup-to-image | \

ssh @ ‘cat > ~/backups/my_backup.img’

hot backup vs online backup

你提到的 hot backuponline backup 的确在某些场景下可以被看作是同一个概念,尤其是它们都允许在数据库运行的同时进行备份,且不会中断数据库的读写操作。然而,它们之间可能有些微的差异或特性,这可能解释为什么某些数据库供应商将它作为一个付费功能。

1. Hot Backup 和 Online Backup 是否一样?

在大多数数据库上下文中,hot backuponline backup 常常可以互换使用,但它们的细节实现可能有区别:

  • Hot Backup 强调的是备份过程中捕获“所有变化”。换句话说,不仅能够备份已有数据,还能捕获备份期间的增量(如新插入或更新的数据)。
  • Online Backup 更广泛地表示备份期间数据库仍可在线运行(处理请求)。

某些数据库供应商可能会细分这两个概念,但总体来说,二者大部分场景下是同一回事。


2. 为什么需要特殊工具或机制?

在逻辑上,--single-transaction 确实可以用于执行一次一致性的在线备份(比如 MySQL 中使用 mysqldump 加上 --single-transaction),但以下几点解释了为什么复杂数据库(比如 Oracle、PostgreSQL 的企业版)会将 hot backup 功能作为付费特性:

a. 事务一致性和并发控制的复杂性

  • 对于支持多事务的数据库,确保备份过程中数据的一致性需要更多的机制。--single-transaction 的实现依赖于快照隔离(snapshot isolation),但这仅适合某些简单的应用场景。
  • 如果数据库的变更复杂(如长事务、触发器或存储过程),实现完全一致性备份就需要数据库引擎额外的处理能力。

b. 物理备份 vs 逻辑备份

  • --single-transaction 通常用于逻辑备份(例如通过 SQL 导出数据)。
  • 热备份工具通常用于 物理备份(直接复制存储文件块),这种方式备份速度更快,尤其适合大数据量的情况。
  • 要实现物理备份的一致性,数据库可能需要跟踪快照点、冻结部分写操作,甚至临时调整存储布局。

c. 增量备份与日志捕获

  • 付费热备功能通常附带对 增量备份日志捕获 的支持。
  • 增量备份允许只备份从上次备份后发生变更的数据,大幅提高备份效率。而捕获日志(如 MySQL 的 binlog 或 PostgreSQL 的 WAL)则需要数据库在备份期间实时同步这些数据。

d. 性能优化

  • 商业数据库供应商通常会优化热备工具,使其在高并发场景下对性能的影响最小。
  • 自行实现的工具如 --single-transaction,可能在备份时引发大量锁竞争或性能抖动。

e. 跨节点或分布式数据库支持

  • 企业版数据库可能需要支持分布式架构的在线备份。这种情况下,维护全局一致性比单节点的 --single-transaction 复杂得多。

3. 为什么要收费?

商业化数据库将 hot backup 定为付费特性,可能是因为以下原因:

  1. 研发和维护成本:热备份功能的开发涉及到底层存储引擎和事务管理的深度优化。
  2. 企业级支持:热备份通常是企业环境才真正需要的功能,针对这些用户收费符合市场逻辑。
  3. 差异化策略:通过将此功能划归到企业版,数据库厂商可以区分免费用户和付费用户,推动订阅收入。

4. 是否有开源替代方案?

如果你觉得热备功能收费不合理,可以考虑开源数据库中的替代方案:

  • MySQL/MariaDBmysqldump + --single-transaction 适用于小规模场景;对于更复杂的需求,可以使用开源工具 Percona XtraBackup。
  • PostgreSQL:pg_basebackup 提供简单可靠的热备方案。
  • MongoDB:社区版支持在线备份,但对于快照一致性,可能需要借助底层文件系统工具(如 LVM)。

总结来说,--single-transaction 在某些场景确实可以胜任在线备份,但它是一个比较基础的实现。而付费的热备工具则更注重性能、灵活性和适应复杂环境。

如何对一个正在运行的python进行进行内存诊断,这个进程的内存一直在增长

对一个正在运行的 Python 进程进行内存诊断,可以分几个步骤进行:


1. 使用外部工具检查进程内存占用

首先确认该进程的内存使用增长情况和趋势:

  • Linux 系统:

    • 使用 tophtop 查看内存增长。

    • 使用 ps 定位内存占用高的进程:

      1
      ps aux | grep python
    • 使用 pmap 查看进程的内存映射:

      1
      pmap <PID>
  • Windows 系统:

    • 在任务管理器中监控 Python 进程的内存使用。
    • 使用 Windows Performance Monitor 或者 Sysinternals 的工具(如 Process Explorer)。

2. 捕获 Python 堆内存信息

使用 Python 专门的工具捕获堆内存信息,分析内存泄漏或者过度增长的原因。

方法 1:tracemalloc

tracemalloc 是 Python 内置的一个模块,可以跟踪内存分配情况,找出内存占用大的对象和增长点。

步骤:

  1. 在代码中插入以下代码段:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import tracemalloc

    tracemalloc.start()

    # 在某些关键点打印内存使用信息
    snapshot = tracemalloc.take_snapshot()
    top_stats = snapshot.statistics('lineno')

    print("[ Top 10 memory-consuming lines ]")
    for stat in top_stats[:10]:
    print(stat)
  2. 也可以定期运行 tracemalloc 来对比两次快照的内存分配:

    1
    2
    3
    4
    5
    6
    snapshot1 = tracemalloc.take_snapshot()
    # 等待一定时间或操作后
    snapshot2 = tracemalloc.take_snapshot()
    stats = snapshot2.compare_to(snapshot1, 'lineno')
    for stat in stats[:10]:
    print(stat)

方法 2:objgraph

objgraph 是一个第三方工具,可以分析 Python 对象的引用关系,找到那些不必要增长的对象。

安装:

1
pip install objgraph

用法:

1
2
3
4
5
6
7
8
9
10
import objgraph

# 打印当前 Python 中引用最多的对象类型
objgraph.show_most_common_types(limit=10)

# 跟踪某种类型对象的增长
objgraph.show_growth()

# 可视化某个对象的引用关系(需要 graphviz 支持)
objgraph.show_backrefs(some_object, filename='backrefs.png')

方法 3:memory_profiler

memory_profiler 是一个简单易用的工具,可以实时监控函数级别的内存变化。

安装:

1
pip install memory_profiler

用法:
在代码中使用装饰器 @profile,标记需要检查内存占用的函数:

1
2
3
4
5
@profile
def my_function():
x = [i for i in range(100000)]
y = [i ** 2 for i in x]
return y

然后使用命令行运行:

1
python -m memory_profiler my_script.py

3. 使用分析器工具

有时需要更多的分析工具:

  • py-spy: 一个性能分析工具,可以附加到正在运行的 Python 进程,支持查看线程堆栈和内存情况。

    1
    py-spy top --pid <PID>
  • heapy(Guppy 模块的一部分):

    1
    pip install guppy3

    然后使用 heapy 检查内存:

    1
    2
    3
    from guppy import hpy
    h = hpy()
    print(h.heap()) # 查看堆的当前使用情况

4. 排查内存泄漏的代码

如果发现内存泄漏,通常问题可能是:

  • 未释放的全局变量或缓存。
  • 循环引用导致的垃圾回收失败(可以用 gc.collect() 强制清理)。
  • 第三方库的 Bug。

使用工具确定问题点后,逐步优化代码。


5. 监控长时间运行的服务

对于长时间运行的服务,比如 Flask/Django 服务,可以结合日志和分析工具定期记录内存使用情况,例如通过 psutil 定时检查。

代码示例:

1
2
3
4
5
import psutil
import os

process = psutil.Process(os.getpid())
print(f"Memory usage: {process.memory_info().rss / 1024 ** 2:.2f} MB")

成语游戏 https://fourwordgame.com/

landing page
https://github.com/Blazity/next-saas-starter


我要做3个node的ES集群,如何做高可用,负载均衡,故障转移

在 Elasticsearch 集群中,高可用负载均衡故障转移是通过合理的节点配置和架构设计实现的。以下是具体实现步骤和建议:


1. 三节点集群的基本架构

节点角色分配

  • 在一个 3 节点的集群中,每个节点应至少包括以下角色:
    • Master 节点(负责集群管理和元数据分发)
    • Data 节点(存储和处理数据)
    • Ingest 节点(预处理数据,非必须,但推荐)

为高可用性,推荐每个节点都同时承担 masterdata 角色。

配置文件(elasticsearch.yml)示例

在每个节点的配置文件中:

公共配置(所有节点共享)

1
2
3
4
5
cluster.name: es-cluster      # 集群名称
node.name: ${HOSTNAME} # 节点名称(推荐使用主机名)
network.host: 0.0.0.0 # 绑定所有接口
discovery.seed_hosts: ["node1-ip", "node2-ip", "node3-ip"] # 集群中的所有节点 IP
cluster.initial_master_nodes: ["node1", "node2", "node3"] # 初始主节点,集群首次启动用

节点专属配置

为每个节点设置唯一名称和角色(在每个节点上修改以下配置):

Node 1 (elasticsearch.yml)
1
node.roles: ["master", "data"]  # 同时作为主节点和数据节点
Node 2 (elasticsearch.yml)
1
node.roles: ["master", "data"]
Node 3 (elasticsearch.yml)
1
node.roles: ["master", "data"]

2. 高可用配置

配置主节点故障转移

在 Elasticsearch 中,至少需要过半数的主节点候选者(master)存活才能维持集群正常运行。因此:

  • 3 个主节点的集群允许 1 个节点故障。
  • 如果主节点候选者不足过半(例如只有 1 个节点存活),集群将无法选主,进入只读模式。

配置建议

  • 确保每个节点的硬件配置相同,分布在不同的物理主机或数据中心。
  • 使用至少 3 个节点作为主节点候选者。

分片和副本的配置

分片(Shard)和副本(Replica)是 Elasticsearch 数据冗余和高可用的核心。

配置建议

  • 主分片:每个索引应合理划分分片数量,通常是数据量的 1.5 倍。

  • 副本:每个主分片至少 1 个副本。对于 3 个节点集群,推荐如下:

    1
    2
    3
    4
    主分片 (P) 和副本 (R) 分布示意:
    Node 1: P1 R2
    Node 2: P2 R3
    Node 3: P3 R1

    这样即使任意一个节点失败,数据仍然可用。

设置副本数量的 API 命令:

1
2
3
4
PUT /_settings
{
"number_of_replicas": 1
}

3. 负载均衡

Elasticsearch 自带负载均衡

Elasticsearch 客户端支持自动负载均衡。当客户端向一个节点发送请求时,该节点会将请求路由到正确的分片。

客户端连接时可配置多个节点:

1
2
3
4
5
6
7
8
9
from elasticsearch import Elasticsearch

es = Elasticsearch(
hosts=[
{"host": "node1-ip", "port": 9200},
{"host": "node2-ip", "port": 9200},
{"host": "node3-ip", "port": 9200},
]
)

外部负载均衡器

使用外部工具(如 NGINX、HAProxy 或 AWS ELB)实现 HTTP 请求的负载均衡。

使用 NGINX 作为负载均衡器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upstream elasticsearch {
server node1-ip:9200;
server node2-ip:9200;
server node3-ip:9200;
}

server {
listen 80;

location / {
proxy_pass http://elasticsearch;
proxy_set_header Host $host;
}
}

4. 故障转移

自动故障转移

Elasticsearch 自带故障转移功能。当一个节点不可用时:

  1. 副本分片会在剩余的节点上发挥作用。
  2. 当节点恢复后,数据会自动重同步。

监控和告警

建议使用以下工具监控节点健康和负载,以便快速响应节点故障:

  • Kibana:内置的监控 UI,可以直观查看集群状态。
  • Elastic Stack(ELK):使用 Beats 采集集群日志和指标。
  • Prometheus + Grafana:监控集群运行状态,设置告警规则。

5. 集群健康检查

健康检查命令

检查集群健康状态:

1
curl -X GET "http://localhost:9200/_cluster/health?pretty"

健康状态:

  • green:集群运行正常,所有主分片和副本分片都可用。
  • yellow:部分副本分片不可用,但主分片正常。
  • red:至少一个主分片不可用。

6. 总结

  • 高可用性:使用 3 个主节点(最少 3 个,保证过半选主)。
  • 负载均衡:配置客户端连接多个节点,或使用 NGINX/HAProxy 实现负载均衡。
  • 故障转移:启用副本分片,确保数据节点失效时仍能访问。

如果有进一步问题,欢迎继续讨论!