ES 倒排索引与行级安全

共 20 题
📑 题目列表 20 题
#
★★★

1. Elasticsearch 倒排索引的结构(term dictionary、posting list、doc values)是怎样的?FST(有限状态转换器)如何压缩前缀查找、加速 term 定位?

请描述 Elasticsearch 倒排索引的组成部分(term dictionary、posting list、doc values),并说明 FST(有限状态转换器)如何压缩前缀查找并加速 term 定位?

  • 倒排索引的三个核心组件及其职责
  • FST 的字典压缩与共享前缀原理
  • doc values 与正向索引的关系

倒排索引由三部分组成:term dictionary(词项字典)保存所有不重复的 term 及其元数据,posting list(倒排表)保存每个 term 对应的 doc id 列表、词频和位置信息,doc values 则是列式存储的正向索引,用于排序、聚合和脚本计算。term dictionary 的常规查找是二分查找,但 ES 使用 FST(有限状态转换器)将 term 字典压缩为一张共享前缀的确定型无环图,通过在构建时合并所有 term 的公共前缀,大幅减少存储空间,同时把 O(log n) 的分块二分查找降为接近 O(term 长度) 的单次遍历,从而加速 term 定位。doc values 本质上是按文档倒排的列式存储,与倒排索引互补,避免了排序聚合时遍历多余文档。

倒排索引解决的是"单词到文档"的映射,而 doc values 解决"文档到字段值"的逆向需求,两者配合覆盖检索与聚合两类场景。FST 的巧妙之处在于把前缀共享变成图的共享节点,既压缩又加速,是 ES 大规模分片下保持字典常驻内存的关键。

{
  "settings": { "index": { "sort.field": "timestamp", "sort.order": "desc" } },
  "mappings": {
    "properties": {
      "category": { "type": "keyword", "doc_values": true },
      "content": { "type": "text", "doc_values": false, "index": true }
    }
  }
}
#
★★★

2. ES 写入流程(写 translog 与内存 buffer → refresh 生成可搜索 segment → flush 持久化并清空 translog)是怎样的?为什么说它是近实时(NRT,默认 1s refresh)?

请描述 Elasticsearch 的写入流程(写入 translog 与内存 buffer、refresh 生成可搜索 segment、flush 持久化并清空 translog),并解释为什么它是近实时(NRT,默认 1s refresh)?

  • refresh 与 flush 的区别及触发时机
  • translog 在崩溃恢复中的作用
  • 近实时性的来源

写入请求先到达 primary shard,文档先写入内存 buffer 和 translog(事务日志),此时数据尚不可搜索。每隔约 1 秒(由 index.refresh_interval 控制)执行一次 refresh,将 buffer 中的文档生成一个内存中的 segment,使数据立即可被搜索,同时清空 buffer。segment 尚未落盘,仍依赖文件系统缓存;当 translog 达到阈值或周期性(默认 30 分钟)触发 flush 时,将内存 segment 真正 fsync 到磁盘并清空 translog。由于数据从写入到可被搜索平均要等待一次 refresh(约 1 秒),因此 ES 是近实时(NRT)而非实时。若节点崩溃,内存中尚未 flush 的 segment 会丢失,但 translog 记录了这些操作,启动时可通过重放 translog 恢复到 last ack 状态。

近实时性源于"refresh 高频、flush 低频"的设计:refresh 让写入快速可见,flush 保证持久化。两者解耦使 ES 在写入吞吐与查询可见性之间取得平衡。translog 是崩溃恢复的兜底,其行为也决定了写入的可靠性级别。

POST /my_index/_refresh
PUT /my_index/_settings
{ "index": { "refresh_interval": "30s", "translog": { "durability": "request" } } }
#
★★★

3. analyzer 的三层结构(char filter、tokenizer、token filter)是什么?中文检索为何常“索引用 ik_max_word、查询用 ik_smart”?

请说明 analyzer 的三层结构(char filter、tokenizer、token filter),并解释中文检索为何常采用"索引用 ik_max_word、查询用 ik_smart"的策略?

  • 分词器三个阶段的处理顺序
  • ik_max_word 与 ik_smart 的差异
  • 索引与查询分词粒度不一致的权衡

analyzer 由三个可选的阶段串联而成:char filter 在分词前对原始文本做字符级预处理(如去除 HTML、替换特殊字符),tokenizer 负责将文本切分成词元 token,token filter 对 token 做增删改(如转小写、去除停用词、词干化、同义词扩展)。对于中文,ik_max_word 会尽可能切出最细的词汇组合(如"中华人民共和国"可切出多个词),召回更全;ik_smart 则只做最可能的粗粒度切分,噪声更少。因此实践中索引用 ik_max_word 以获得更细的索引覆盖、提高召回,查询用 ik_smart 做更精准的切分、减少误匹配,从而在召回率与精确率之间取得平衡。

索引和查询使用不同的分词器在 ES 中是被允许的,因为索引分词决定哪些词可被检索,查询分词决定用户输入如何被切分匹配。这样的"细索引、粗查询"组合是中文检索的常见工程实践,但需要保证扩展词库、同义词配置一致,否则可能出现匹配不到的情况。

{
  "settings": {
    "analysis": {
      "analyzer": {
        "index_analyzer": { "type": "ik", "tokenizer": "ik_max_word" },
        "query_analyzer": { "type": "ik", "tokenizer": "ik_smart" }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": { "type": "text", "analyzer": "index_analyzer", "search_analyzer": "query_analyzer" }
    }
  }
}
#
★★★

4. ES 深度分页 from+size 为什么有 max_result_window(默认 1 万)限制(每个 shard 都要返回 top N 给协调节点归并)?scroll 与 search_after 分别如何解决深分页?

请解释 ES 深度分页 from+size 为什么受 max_result_window(默认 1 万)限制,并说明 scroll 与 search_after 分别如何解决深分页问题?

  • from+size 的分页原理与开销
  • 协调节点归并的代价
  • scroll 与 search_after 的适用场景

使用 from+size 时,每个分片都要把 from+size 条结果都返回给协调节点,协调节点再对全部分片结果做归并排序,最后截取第 from 到 from+size 条。当 from 很大时,每个分片都要传输和排序大量候选文档,内存与 CPU 开销随深度线性增长,因此默认 max_result_window 为 1 万条,防止深分页拖垮集群。scroll 通过保存一个快照上下文(search context)在服务端维护游标,适合一次拉取大量数据(如导出、数据迁移),但不适合实时分页。search_after 通过上一页最后一个文档的排序值作为游标继续翻页,本质是"基于上一页位置"的深度分页,每次只向后取 size 条,避免归并深层数据,适合用户实时翻页。search_after 需要配合唯一且有稳定排序的字段(如 _id 或时间戳)保证分页稳定。

深分页的核心矛盾是"每个分片都要扫描到足够深度"。scroll 用服务端快照避免重复计算但快照陈旧且占用资源;search_after 用游标实现增量翻页,代价小且一致性好,是 OLAP 型实时分页的首选。

GET /my_index/_search
{
  "size": 10,
  "sort": [ { "timestamp": "desc" }, { "_id": "asc" } ],
  "search_after": [ "2026-08-01T00:00:00Z", "doc_000123" ]
}
#
★★★

5. ES 分片(shard)与副本(replica)如何影响写入一致性(wait_for_active_shards)与读吞吐?分片数量与单分片大小(建议 10-50GB)如何规划?

请说明 ES 分片(shard)与副本(replica)如何影响写入一致性(wait_for_active_shards)与读吞吐,并介绍分片数量与单分片大小(建议 10-50GB)的规划原则?

  • 分片与副本的读写角色
  • wait_for_active_shards 的写入语义
  • 分片数量规划的权衡

分片是数据分布与并行化的基本单元,主分片承担写入,副本分片既提供故障冗余又分担读流量,因此增加副本数可提升读吞吐,但每条写入也要复制到每个 active 副本,会降低写吞吐。wait_for_active_shards 控制写入前至少需要多少个分片副本处于 active 状态(默认 1,即仅主分片),更高的值能保证副本已就绪再确认写入,牺牲一致性换取更强的可用性保证。分片数量规划上,单分片建议控制在 10-50GB,原因是分片太多会导致每个分片过小、元数据与查询归并开销大;分片太少又无法充分利用多节点并行。总数据量除以目标单分片大小得到合理分片数,并需考虑主分片在索引生命周期内不可再改,副本数可动态调整。

分片数量在创建索引时确定后不可改变,因此规划要基于数据增长上限。副本数可随时调整。写入一致性由 wait_for_active_shards 与 replication 语义共同决定,读吞吐则由副本并行承担,二者在副本数上存在此消彼长的关系。

PUT /my_index
{
  "settings": { "number_of_shards": 5, "number_of_replicas": 1, "index.write.wait_for_active_shards": 2 }
}
#
★★★

6. segment merge 的机制与代价(后台合并小段、force_merge 的写放大与 IO 峰值)是什么?对写入吞吐与查询延迟有何影响?

请说明 Elasticsearch segment merge 的机制与代价(后台合并小段、force_merge 的写放大与 IO 峰值),并分析其对写入吞吐与查询延迟的影响?

  • segment 合并的触发条件与策略
  • force_merge 的写放大与 IO 峰值
  • 合并对读写性能的双向影响

ES 的索引由多个 segment 组成,每次 refresh 产生一个新 segment,segment 数量过多会降低查询效率并增加文件句柄。Lucene 在后台按合并策略(如 tiered merge)挑选大小相近的 segment 合并为更大的 segment,合并过程会重写数据,产生写放大。默认后台合并是异步、低优先级进行的,会占用 IO 与 CPU,可能影响并发写入;但合理的合并能减少 segment 数量、提升查询速度。force_merge 可强制把索引合并到指定的少量 segment(如 max_num_segments=1),适合只读或归档索引,但会一次性产生显著的写放大与 IO 峰值,耗时较长,不应在写入高峰期执行。对热索引,频繁的小合并会消耗写入 IO;对热查询,segment 越少查询越快。因此常通过 index.merge.policy 参数平衡合并策略,或对只读索引定期 force_merge。

合并的本质是用写放大换取查询性能与文件管理效率。force_merge 是"一次性集中写放大",适合离线就绪的只读索引;后台 tiered merge 是"持续低频写放大",适合实时写入的索引。两者取舍取决于索引的读写比例。

POST /archive_index/_forcemerge?max_num_segments=1
PUT /hot_index/_settings
{ "index.merge.policy.segments_per_tier": 10, "index.merge.policy.max_merged_segment": "5gb" }
#
★★★

7. mapping 中 text 与 keyword 类型的差异(分词 vs 不分词、能否聚合排序)是什么?动态映射(dynamic mapping)有何风险、如何用 dynamic template 规范?

请说明 mapping 中 text 与 keyword 类型的差异(分词 vs 不分词、能否聚合排序),并分析动态映射(dynamic mapping)的风险及如何用 dynamic template 规范?

  • text 与 keyword 的字段语义差异
  • 聚合排序对字段类型的要求
  • dynamic mapping 的风险与 dynamic template 的应用

text 类型会经过分词器切分为多个词元,支持全文检索,但默认不能被聚合、排序;keyword 类型不分词,作为整体精确匹配,支持聚合、排序、精确查询。对于需要同时做全文检索和精确聚合的字段,常用"text + keyword 多字段"(multi-field)方案,例如 title 为 text 用于搜索,title.keyword 为 keyword 用于聚合排序。动态映射会在写入新字段时自动推断类型,风险是字段类型一旦建立不可更改、可能产生大量无用字段消耗资源、或误判类型(如把数字当 keyword)导致无法正确聚合。dynamic template 可以在字段进入时按名称或类型匹配预设映射规则,从而对动态字段进行规范化控制。

选择字段类型直接决定检索能力与存储成本。text 适合全文语义检索,keyword 适合精确过滤、聚合、排序。动态映射虽然方便,但生产环境应通过 dynamic template 或显式 mapping 约束,避免字段类型失控与资源浪费。

{
  "mappings": {
    "dynamic_templates": [
      { "strings_as_keyword": { "match_mapping_type": "string", "mapping": { "type": "keyword" } } }
    ],
    "properties": {
      "title": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }
    }
  }
}
#
★★

8. bool/match/term/range 查询 DSL 中 filter 上下文(不评分、可缓存)与 query 上下文有何区别?如何用 filter 优化性能?

请说明 bool/match/term/range 查询 DSL 中 filter 上下文(不评分、可缓存)与 query 上下文有何区别,并解释如何用 filter 优化性能?

  • filter 与 query 上下文的评分差异
  • filter 的缓存机制
  • 常见查询子句上下文的区分

在 ES 的 bool 查询中,must 与 should 子句属于 query 上下文,会参与相关性评分计算,而 filter 子句属于 filter 上下文,只做过滤匹配、不参与评分。filter 上下文的匹配结果会被缓存(filter cache),因此对于状态、时间范围、分类等高频且相对稳定的过滤条件,放在 filter 子句既可以避免评分开销,又能利用缓存加速,是常见的性能优化手段。match 查询用于全文检索(进行分词),term 用于精确匹配(不分词),range 用于范围过滤,它们放在 filter 上下文时同样享受不评分与缓存收益。使用 filter 还会让 bool 查询更简洁,因为无需额外设置"评分无关"的嵌套结构。

判断一个子句属于哪个上下文的规律是:bool 查询的 must/must_not/should 为 query 上下文,filter 为 filter 上下文;constant_score 的 filter 也是 filter 上下文。将稳定的过滤条件放进 filter 上下文是在不改变结果的前提下显著降低查询开销的关键技巧。

{
  "query": {
    "bool": {
      "filter": [
        { "term": { "status": "active" } },
        { "range": { "created_at": { "gte": "2026-01-01" } } }
      ],
      "must": [ { "match": { "title": "elasticsearch" } } ]
    }
  }
}
#
★★

9. ES 7.x+ 主节点选举如何从 zen discovery(minimum_master_nodes 手动配置)演进为类 Raft 协议?如何防止脑裂?

请说明 ES 7.x+ 主节点选举如何从 zen discovery(minimum_master_nodes 手动配置)演进为类 Raft 协议,并解释如何防止脑裂?

  • zen discovery 与 minimum_master_nodes
  • 类 Raft 协议(quorum-based)的选举机制
  • 脑裂的成因与防护

在早期版本,ES 使用 zen discovery,通过手动配置 discovery.zen.minimum_master_nodes 指定参与选举的法定人数(通常为节点数/2+1),防止多个主节点同时存在(脑裂)。该配置需要人工维护且易错配。从 7.x 开始,ES 引入基于 quorum 的类 Raft 共识协议(使用奇数的 master-eligible 节点数,法定人数取 n/2+1),主节点选举由协议自动决出,无需手动配置 minimum_master_nodes,并废弃了 zen discovery。为防止脑裂,核心是保证任意时刻只有一个主节点:主节点必须获得多数派(quorum)的支持才能当选,且网络分区时只有包含多数派的分区才能选出主节点,少数派分区无法独立成主。同时,ES 会通过故障检测与 master 节点的 ping 机制确认主节点存活。

脑裂的根源是"两个分区各自认为自己是主"。Raft 的 quorum 机制天然保证只有过半数的分区能达成法定选举,从而避免双主。相比手动配置,类 Raft 协议更可靠、更自动化,是 7.x 演进的核心价值。

# elasticsearch.yml
discovery.seed_hosts: ["es-node1", "es-node2", "es-node3"]
cluster.initial_master_nodes: ["es-node1", "es-node2", "es-node3"]
#
★★

10. MySQL 中视图与函数的权限隔离?

请说明 MySQL 中视图与函数的权限隔离机制?

  • 视图的权限控制与 SQL 权限
  • 存储函数与存储过程的权限
  • 权限隔离的意义

MySQL 通过基于权限表的授权机制对视图和函数进行权限隔离。视图可以设置 SQL SECURITY 为 DEFINER 或 INVOKER:DEFINER 表示执行视图时以定义者的权限来解析底层表,INVOKER 表示以调用者的权限执行,后者可实现更严格的隔离,防止低权限用户通过视图越权访问底层表。函数和存储过程同样支持 SQL SECURITY DEFINER/INVOKER,且可精确授予 EXECUTE 权限。视图还可以通过 SELECT 的列限制与 WHERE 条件对数据做行级、列级裁剪,从而在不暴露底层表的前提下提供受限数据访问。这种"通过视图隐藏表、通过 DEFINER 控制解析权限"的机制是数据库权限隔离的重要手段。

权限隔离的核心是"最小暴露、按需授权"。视图和函数作为数据访问的中间层,能限制用户直接访问底层表,并通过 SQL SECURITY 决定权限解析的主体,从而在应用层与 DBA 之间形成安全边界。

CREATE VIEW v_employee AS SELECT id, name FROM employee WHERE dept = 'IT';
GRANT SELECT ON db.v_employee TO 'readonly'@'%';
CREATE FUNCTION get_count() RETURNS INT SQL SECURITY DEFINER RETURN (SELECT COUNT(*) FROM employee);
#
★★

11. BM25 相关性评分的核心因子(词频饱和、逆文档频率 IDF、字段长度归一化)是什么?相比 TF-IDF 做了哪些改进?

请说明 BM25 相关性评分的核心因子(词频饱和、逆文档频率 IDF、字段长度归一化),并说明相比 TF-IDF 做了哪些改进?

  • BM25 的三大核心因子
  • 词频饱和与 k1、b 参数
  • 相比 TF-IDF 的改进

BM25 是 ES 默认的相关性评分算法,其核心受三个因子影响:词频饱和(TF)、逆文档频率(IDF)和字段长度归一化。与经典 TF-IDF 不同,BM25 通过参数 k1 对词频做饱和处理,使某个词在文档中出现次数对得分的贡献呈非线性增长——词频达到一定次数后边际收益递减,避免高频词主导结果;IDF 反映词的区分度,词越稀有权重越高;字段长度归一化由参数 b 控制,字段越长其词频权重越低,因为长文档命中一个词相对更"普通"。相比 TF-IDF,BM25 的改进在于:词频不再线性增长而是饱和,长文档的惩罚更具归一化,且两个可调参数使评分更稳健、更贴合真实检索。

TF-IDF 的缺陷是词频线性放大、长文档无归一化,容易让高频词和长文档主导。BM25 用饱和函数和长度归一化修正了这些偏差,使评分更符合"词出现越多说明越相关,但不会无限相关"的直觉。

{ "settings": { "index": { "similarity": { "default": { "type": "BM25", "k1": 1.2, "b": 0.75 } } } } }
#
★★

12. ABAC(Attribute-Based Access Control),基于属性的访问控制?

请说明 ABAC(Attribute-Based Access Control,基于属性的访问控制)的概念与机制?

  • ABAC 的属性维度(主体、资源、环境、动作)
  • 策略与规则引擎
  • 与 RBAC 的对比

ABAC 是基于属性进行访问控制的模型,通过主体属性(用户、角色、部门)、资源属性(数据表、字段、记录级别)、环境属性(时间、地点、设备、网络状态)和动作属性(读、写、执行)的组合,配合策略(policy)与规则引擎动态判定是否授权。例如"仅当用户部门=财务 且 时间在工作时间 且 访问资源为财务报表时允许读取"。ABAC 最大的优势是细粒度、动态和上下文感知,能支持复杂的条件授权,适合大数据与云环境下的精细化权限控制。其代价是策略复杂、规则引擎开销大、管理难度高。相比 RBAC 基于预定义角色,ABAC 更灵活,但通常与 RBAC 结合使用(角色决定基础权限,属性决定细粒度扩展)。

ABAC 的核心是把授权从"你是谁"扩展到"什么条件组合下允许什么",使权限决策具备上下文感知能力。策略引擎每次请求都会评估组合条件,因而更精细但也更复杂,适合需要动态、多维授权的场景。

#
★★

13. RBAC(Role-Based Access Control),基于角色的访问控制?

请说明 RBAC(Role-Based Access Control,基于角色的访问控制)的概念与机制?

  • RBAC 的角色-权限-用户关系
  • 角色分配与权限继承
  • 最小权限的实现

RBAC 通过角色作为中间层连接用户与权限:权限被授予角色,角色被分配给用户,用户通过角色获得权限。这种"用户-角色-权限"的三层模型简化了权限管理,当人员变动时只需调整角色分配,权限集中定义在角色上,便于复用与审计。RBAC 支持角色之间的继承与层次关系,角色数量远小于用户数,降低了管理成本。它天然契合最小权限原则:为每个角色只授予完成其职责所需的最小权限,按需分配角色。RBAC 是数据库、应用系统中最主流、最易理解的访问控制模型,但它的粒度受限于角色设计,对"基于条件"的精细授权不如 ABAC 灵活,通常与 ABAC、行级安全结合使用。

RBAC 的价值在于把权限从"零散授予用户"重构为"集中定义在角色",让授权可预测、可审计、可批量管理。它牺牲了个体级的微调灵活性,换取运维的简单与安全。

#
★★

14. 最小权限原则(Principle of Least Privilege)的实践?

请说明最小权限原则(Principle of Least Privilege)的实践方法?

  • 最小权限原则的定义
  • 数据库账号与权限的实践
  • 与职责分离、审计的关系

最小权限原则要求每个主体(用户、进程、函数)只被授予完成其任务所必需的最小权限,并限制其权限范围与有效期。数据库实践包括:为应用使用独立账号并按库表授予最小权限(如只读应用只给 SELECT,写应用只给 INSERT/UPDATE/DELETE),避免使用拥有全部权限的超级账号;区分业务账号与运维账号,运维账号仅在需要时临时提升权限;对敏感操作采用临时授权并自动回收;定期审计和回收多余权限。该原则与职责分离(SoD)配合,防止单一主体权限过大导致误操作或滥用,同时降低被攻破后的影响面。

最小权限是纵深防御的基石:即使应用被攻破,受限的权限也能限制攻击者能造成的破坏。它通过"按需授权、定期回收、权限审计"三个环节落地,是数据库安全审查(如等保、PCI DSS)的常见要求。

#
★★

15. 数据库认证方式,密码、证书、Kerberos、LDAP、OAuth?

请说明数据库认证方式的分类:密码、证书、Kerberos、LDAP、OAuth 各自的机制与适用场景?

  • 各类认证方式的工作原理
  • 企业级统一认证
  • 各种方式的优缺点

数据库认证方式包括:密码认证(最常用,使用用户名密码,需配合强密码策略与加密传输);证书认证(基于 TLS 客户端证书,客户端持有证书私钥,服务端验证证书指纹,适合机器对机器的安全连接);Kerberos(基于第三方 KDC 颁发票据的互认认证,适合大型企业域环境,实现单点登录与双向认证);LDAP(通过外部目录服务验证用户身份,适合企业统一身份目录,便于集中管理但需配置 LDAP 服务器);OAuth(用于授权第三方应用代表用户访问,通常配合身份提供方 IdP 实现 SSO 与令牌托管)。实际生产中常将多种方式组合:密码用于开发测试,Kerberos/LDAP 用于企业统一入口,证书用于服务间 mTLS,OAuth 用于应用层授权。

认证方式的选择取决于信任模型与运维复杂度。密码简单但易被爆破,需配合账户锁定与传输加密;证书与 Kerberos 提供更强机器级认证;LDAP 与 OAuth 聚焦企业统一身份与单点登录。安全设计应优先采用强认证并组合使用。

#
★★

16. MFA(Multi-Factor Authentication)在数据库的应用?

请说明 MFA(Multi-Factor Authentication,多因素认证)在数据库中的应用?

  • 多因素认证的要素类型
  • 数据库管理场景的 MFA
  • 与数据库权限的结合

MFA 要求用户通过两种或以上不同类型的因素完成认证,通常组合"你知道的"(密码)、"你拥有的"(令牌、OTP、证书、手机)、"你是的"(生物特征)三类因素。在数据库场景中,MFA 主要应用于管理员与运维人员的高权限操作,例如 DBA 登录数据库运维平台时,需在密码之外再输入一次性验证码(OTP)或使用硬件密钥,才能执行高危运维动作。由于数据库协议本身通常不支持 MFA,实践中通过独立认证网关、代理(如 ProxySQL、堡垒机)或身份提供方(IdP)在应用层叠加 MFA,认证通过后再发放短期数据库凭证。MFA 能显著降低口令泄露与暴力破解带来的风险,是高权限操作的关键防线。

数据库 MFA 的难点在于原生协议限制,因此落地通常依赖认证网关或代理层。它把"知道凭证"升级为"多因素确认",即使密码被窃取,攻击者也无法仅凭密码完成高权限操作。

#
★★

17. MySQL 中用户、权限、角色的管理?

请说明 MySQL 中用户、权限、角色的管理方式?

  • 用户创建与主机绑定
  • 权限的粒度(库、表、列)
  • 角色与权限的关联

MySQL 通过 CREATE USER 创建用户,用户通常绑定主机(host),如 'user'@'10.0.0.%' 表示仅允许该网段登录。权限通过 GRANT 授予,粒度覆盖全局、数据库、表、列和存储过程级别,如 GRANT SELECT, INSERT ON db.table TO 'user'@'host'。角色(从 8.0 起支持)是一个权限集合,创建角色后把权限授予角色,再把角色授予用户,用户通过 SET ROLE 或 DEFAULT ROLE 激活角色获得权限,从而简化多用户权限管理。权限的管理还包括 REVOKE 回收权限、FLUSH PRIVILEGES 刷新权限(8.0 后 GRANT 自动生效)、SHOW GRANTS 查看权限。审计上应定期检查各用户权限,避免权限过大。

MySQL 的用户管理特点是"用户+主机"二元身份与细粒度授权。角色机制把常用权限组合成可复用单元,提升了管理效率并符合最小权限实践。理解权限层级(global→db→table→column)是正确授权的关键。

CREATE USER 'app'@'10.0.0.%' IDENTIFIED BY 'StrongPass!';
CREATE ROLE 'readonly_role';
GRANT SELECT ON mydb.* TO 'readonly_role';
GRANT 'readonly_role' TO 'app'@'10.0.0.%';
SET DEFAULT ROLE 'readonly_role' FOR 'app'@'10.0.0.%';
#
★★

18. PostgreSQL 的角色?

请说明 PostgreSQL 角色(role)的概念与管理机制?

  • 角色与用户的统一
  • 角色的属性与继承
  • 成员关系与权限

PostgreSQL 中角色(role)是统一的"用户"与"组"概念,可以是一个登录用户,也可以是一个权限集合(组角色)。角色通过 CREATE ROLE 创建,可设置属性如 LOGIN(能否登录)、SUPERUSER(超级用户)、CREATEDB、CREATEROLE 等。角色之间通过 GRANT 建立成员关系(membership),一个角色可成为另一个角色的成员从而继承其权限,但默认成员不自动继承 SUPERUSER 等特殊属性,需通过 SET ROLE 切换到目标角色。权限授予基于对象(表、schema、函数、序列)并由 GRANT/REVOKE 控制,PUBLIC 角色默认可访问 public schema。PostgreSQL 的角色模型比 MySQL 更灵活,把用户与组统一为一种抽象,便于复杂权限继承。

PostgreSQL 的"角色即用户或组"的设计简化了权限模型:没有独立的 user 与 role 两类,而是用角色属性区分。成员关系与继承让权限组合更灵活,但需要理解默认不继承特殊属性的行为,避免权限预期偏差。

CREATE ROLE app_user LOGIN PASSWORD 'secret';
CREATE ROLE app_group;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_group;
GRANT app_group TO app_user;
#
★★

19. Elasticsearch 9.x 相对 8.x 的大版本升级路径,废弃 API 与默认行为变更、kNN 向量检索与语义搜索的演进如何评估?

请评估 Elasticsearch 9.x 相对 8.x 的大版本升级路径,包括废弃 API 与默认行为变更、kNN 向量检索与语义搜索的演进?

  • 大版本升级的风险评估
  • 废弃 API 与行为变更
  • 向量检索与语义搜索的演进

从 8.x 升级到 9.x 属于大版本升级,涉及废弃 API 与默认行为变更,需先评估影响面。升级前应梳理应用在 8.x 上使用的 API 是否已被标记废弃(如某些 _type、_search 参数、旧版安全设置),因为 9.x 会移除这些废弃项;同时关注默认行为变化(如安全默认启用、索引默认配置、分片放置策略)可能导致的差异。评估的维度包括:兼容性测试(在 staging 环境跑全量测试)、查询与 mapping 的兼容性、插件与客户端版本、以及集群滚动升级的可行性。在向量检索与语义搜索方面,9.x 继续演进 kNN 向量检索与稠密向量字段,提升向量索引效率与语义检索能力,升级时需确认向量字段类型、向量存储与 scoring 的默认行为是否变化,并评估是否将新的语义检索能力(如多项推理、混合检索 RRF)纳入应用。

大版本升级的关键是先识别"废弃即移除"的 API 与行为变化,再通过测试验证兼容性。向量检索作为新兴能力,升级评估既要看旧功能是否保留,也要看新能力是否值得引入,属于"兼容性 + 技术演进"的双重评估。

#

20. Elasticsearch 的 ILM(Index Lifecycle Management)如何用 hot→warm→cold→frozen→delete 五阶段管理索引生命周期?rollover、shrink、force merge 与 searchable snapshot 分别在哪个阶段触发,各阶段索引的 read-only 与副本数如何自动切换?

请说明 Elasticsearch 的 ILM(Index Lifecycle Management)如何用 hot→warm→cold→frozen→delete 五阶段管理索引生命周期,并说明 rollover、shrink、force merge 与 searchable snapshot 分别在哪个阶段触发,以及各阶段索引的 read-only 与副本数如何自动切换?

  • ILM 五阶段的生命周期模型
  • rollover/shrink/force_merge/searchable snapshot 的触发时机
  • 各阶段 read-only 与副本数的切换

ILM 将索引生命周期划分为 hot(热)、warm(温)、cold(冷)、frozen(冻结)、delete(删除)五个阶段,通过策略(policy)定义各阶段的条件与动作。hot 阶段负责实时写入,常通过 rollover 按文档数、大小或时间滚动创建新索引,避免单索引过大;条件满足后进入 warm 阶段,此时可执行 shrink 将主分片数缩减、force_merge 将小段合并减少段数,并把索引设为 read-only(保证不再写入);进入 cold 阶段后索引通常较冷,可用 searchable snapshot 将数据迁移到快照存储以释放本地磁盘,同时保持可查询;frozen 阶段进一步降低资源占用,几乎完全依赖快照,查询延迟更高;delete 阶段按保留期限删除索引并释放资源。各阶段副本数会自动切换:hot 阶段保留较多副本以保障写入与读性能,warm/cold 阶段可降低副本数甚至为 0(依赖快照或后台存储),从而节省存储。read-only 通过 index.blocks.write 在 warm 之后自动开启,保证不再写入。

ILM 的价值是让索引生命周期自动化,减少人工干预。核心是让"热的资源多用、冷的数据降级",通过 rollover 控制分片规模、shrink 减少分片、force_merge 优化段、searchable snapshot 把冷数据下沉到低成本存储,并在各阶段自动切换 read-only 与副本数,实现成本与性能的平衡。

PUT /_ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot":   { "actions": { "rollover": { "max_size": "50gb", "max_age": "30d" } } },
      "warm":  { "actions": { "shrink": { "number_of_shards": 2 }, "forcemerge": { "max_num_segments": 1 }, "readonly": {} } },
      "cold":  { "actions": { "searchable_snapshot": { "snapshot_repository": "backup" } } },
      "delete":{ "min_age": "180d", "actions": { "delete": {} } }
    }
  }
}