Elasticsearch 索引数据量激增的应对与优化:从原理到部署实践

news2025/4/19 0:16:45

Elasticsearch(ES)作为一款强大的分布式搜索和分析引擎,广泛应用于日志分析、全文搜索和实时数据处理等场景。然而,随着数据量激增,索引可能面临性能瓶颈,如写入变慢、查询延迟高或存储成本上升。如何有效应对数据量增长,并通过调优和部署优化确保系统高效运行,是 Java 开发者在使用 ES 时必须解决的难题。本文将深入探讨 Elasticsearch 索引数据量激增的应对策略,覆盖数据管理、性能调优和集群部署,并结合 Java 代码实现一个支持大数据量索引的日志系统。


一、索引数据量激增的挑战

1. 什么是索引数据量激增?

在 Elasticsearch 中,索引数据量激增指单个索引或集群存储的文档数量和体积显著增长,常见于:

  • 日志系统:每天生成数百万日志。
  • 电商搜索:商品数据随业务扩展快速累积。
  • 监控平台:传感器或服务器产生高频数据。

典型场景下,索引可能从 GB 级增长到 TB 级,甚至 PB 级。

2. 数据量激增的影响

  • 性能下降
    • 写入性能:批量索引变慢,刷新(refresh)开销增加。
    • 查询性能:扫描更多分片和段,导致延迟升高。
  • 存储压力
    • 磁盘占用激增,成本上升。
    • 分片过多导致管理开销大。
  • 集群稳定性
    • 节点过载,GC 频繁。
    • 分片分配不均,热点问题。
  • 资源瓶颈
    • CPU、内存和 IO 达到上限。
    • 网络带宽受限,副本同步延迟。

3. 应对目标

  • 高效写入:支持高吞吐索引。
  • 快速查询:保持亚秒级响应。
  • 存储优化:降低磁盘和成本。
  • 集群扩展:动态适应数据增长。

二、应对索引数据量激增的策略

以下从数据管理、性能调优和集群部署三个维度分析应对手段。

1. 数据管理策略

原理
  • 索引结构
    • 索引由分片组成,每个分片是 Lucene 索引。
    • 分片过多增加管理开销,过少限制并行性。
  • 数据生命周期
    • 数据有冷热阶段(如日志随时间变冷)。
    • 过期数据无需实时查询。
  • 瓶颈
    • 单索引过大导致查询慢。
    • 冗余字段占用存储。
    • 缺乏分区管理数据膨胀。
优化策略
  • 时间分片索引
    • 按时间(如每天/每月)创建索引。
    • 例:logs-2025.04.12,便于滚动和删除。
  • 索引生命周期管理(ILM)
    • 定义阶段(Hot、Warm、Cold、Delete)。
    • 自动滚动、压缩和删除。
  • 精简映射
    • 禁用动态映射(dynamic: strict)。
    • 仅索引必要字段,禁用 _allnorms
  • 数据分区
    • 按业务(如用户、地域)拆分索引。
    • 例:orders-user1-2025.04
  • 压缩存储
    • 使用 index.codec: best_compression
    • 合并段(force_merge)减少存储。

示例:ILM 策略

PUT _ilm/policy/log_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "7d"
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "allocate": { "require": { "data": "warm" } },
          "forcemerge": { "max_num_segments": 1 },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": { "require": { "data": "cold" } },
          "set_priority": { "priority": 0 }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

应用 ILM

PUT logs-000001
{
  "settings": {
    "index.lifecycle.name": "log_policy",
    "index.lifecycle.rollover_alias": "logs"
  }
}

2. 性能调优策略

原理
  • 写入性能
    • 批量索引和刷新频率影响吞吐。
    • 副本同步增加延迟。
  • 查询性能
    • 分片数和段数决定扫描成本。
    • 深翻页和复杂聚合耗资源。
  • 存储效率
    • Lucene 段碎片浪费空间。
    • 冗余分词增加索引大小。
  • 瓶颈
    • 频繁刷新导致写入阻塞。
    • 分片过多增加查询开销。
    • 垃圾回收(GC)停顿。
优化策略
  • 批量写入
    • 使用 Bulk API,批次大小控制在 5-15MB。
    • 异步写入,减少客户端等待。
  • 刷新优化
    • 增大 index.refresh_interval(如 30s)。
    • 实时性要求低时设为 -1,手动刷新。
  • 分片优化
    • 分片大小 20-50GB,节点分片数不超过 20 * CPU 核心数
    • 副本数 1-2,平衡查询和容错。
  • 查询优化
    • 使用 search_after 替代深翻页。
    • 优先 filter 减少评分开销。
    • 限制聚合范围(如 terms 桶大小)。
  • 段合并
    • 定期 POST my_index/_forcemerge?max_num_segments=1
    • 注意:仅对只读索引操作。
  • 分词优化
    • 使用轻量分词器(如 standardkeyword)。
    • 中文场景:ik_smart 替代 ik_max_word

示例:批量写入设置

PUT my_index/_settings
{
  "index": {
    "refresh_interval": "30s",
    "number_of_shards": 5,
    "number_of_replicas": 1,
    "codec": "best_compression"
  }
}

3. 集群部署策略

原理
  • 节点角色
    • 数据节点:存储和查询。
    • 主节点:管理集群状态。
    • 协调节点:分发查询和合并结果。
  • 硬件资源
    • CPU:影响索引和查询速度。
    • 内存:堆(JVM)和系统缓存各占 50%。
    • 磁盘:SSD 优于 HDD。
  • 瓶颈
    • 单节点过载导致宕机。
    • 分片分配不均造成热点。
    • 网络延迟影响副本同步。
优化策略
  • 冷热分离
    • 热节点(SSD、高性能 CPU)处理新数据。
    • 冷节点(HDD、大容量)存储历史数据。
    • 配置:node.attr.data: hot/cold
  • 节点配置
    • 数据节点:16-32GB 堆,8-16 核 CPU,SSD。
    • 主节点:4-8GB 堆,4 核 CPU,专注协调。
    • 协调节点:8-16GB 堆,优化查询分发。
  • 分片均衡
    • 启用 cluster.routing.allocation.balance.shard
    • 限制单节点分片(total_shards_per_node)。
  • JVM 调优
    • 堆大小:节点内存的 50%,最大 31GB。
    • 使用 G1 GC(-XX:+UseG1GC)。
    • 禁用 Swap(swapoff -a)。
  • 扩展集群
    • 动态添加节点,触发分片重分配。
    • 使用 _cluster/reroute 手动优化。
  • 监控与报警
    • 使用 Kibana 或 cat APIs 监控分片、节点和堆。
    • 设置慢查询日志(index.search.slowlog.threshold.query.warn=10s)。

示例:冷热分离

# elasticsearch.yml(热节点)
node.attr.data: hot
node.roles: [data]

# elasticsearch.yml(冷节点)
node.attr.data: cold
node.roles: [data]

JVM 配置

# jvm.options
-Xms16g
-Xmx16g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200

三、Java 实践:实现大数据量日志索引系统

以下通过 Spring Boot 和 Elasticsearch Java API 实现一个支持大数据量索引的日志系统,综合应用优化策略。

1. 环境准备

  • 依赖pom.xml):
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.17.9</version>
    </dependency>
</dependencies>

2. 核心组件设计

  • LogEntry:日志实体。
  • ElasticsearchClient:封装批量索引和查询。
  • LogService:业务逻辑,支持高效写入和搜索。
LogEntry 类
public class LogEntry {
    private String id;
    private String message;
    private String level;
    private long timestamp;

    public LogEntry(String id, String message, String level, long timestamp) {
        this.id = id;
        this.message = message;
        this.level = level;
        this.timestamp = timestamp;
    }

    // Getters and setters
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public String getLevel() { return level; }
    public void setLevel(String level) { this.level = level; }
    public long getTimestamp() { return timestamp; }
    public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
}
ElasticsearchClient 类
@Component
public class ElasticsearchClient {
    private final RestHighLevelClient client;

    public ElasticsearchClient() {
        client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );
    }

    public void bulkIndex(List<LogEntry> logs, String indexName) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        for (LogEntry log : logs) {
            Map<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("message", log.getMessage());
            jsonMap.put("level", log.getLevel());
            jsonMap.put("timestamp", log.getTimestamp());
            bulkRequest.add(new IndexRequest(indexName)
                .id(log.getId())
                .source(jsonMap));
        }
        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.NONE);
        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (response.hasFailures()) {
            throw new IOException("Bulk index failed: " + response.buildFailureMessage());
        }
    }

    public List<LogEntry> search(
        String indexName,
        String query,
        String level,
        Long lastTimestamp,
        int size
    ) throws IOException {
        SearchRequest searchRequest = new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.filter(QueryBuilders.rangeQuery("timestamp").gte("now-7d"));
        if (level != null) {
            boolQuery.filter(QueryBuilders.termQuery("level", level));
        }
        if (query != null) {
            boolQuery.must(QueryBuilders.matchQuery("message", query));
        }

        sourceBuilder.query(boolQuery);
        sourceBuilder.size(size);
        sourceBuilder.sort("timestamp", SortOrder.DESC);
        sourceBuilder.fetchSource(new String[]{"message", "level", "timestamp"}, null);
        if (lastTimestamp != null) {
            sourceBuilder.searchAfter(new Object[]{lastTimestamp});
        }

        searchRequest.source(sourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        List<LogEntry> results = new ArrayList<>();
        for (SearchHit hit : response.getHits()) {
            Map<String, Object> source = hit.getSourceAsMap();
            results.add(new LogEntry(
                hit.getId(),
                (String) source.get("message"),
                (String) source.get("level"),
                ((Number) source.get("timestamp")).longValue()
            ));
        }
        return results;
    }

    @PreDestroy
    public void close() throws IOException {
        client.close();
    }
}
LogService 类
@Service
public class LogService {
    private final ElasticsearchClient esClient;
    private final Queue<LogEntry> buffer = new LinkedList<>();
    private static final int BATCH_SIZE = 100;
    private final String indexPrefix = "logs-";
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");

    @Autowired
    public LogService(ElasticsearchClient esClient) {
        this.esClient = esClient;
    }

    public void addLog(String message, String level) throws IOException {
        LogEntry log = new LogEntry(
            UUID.randomUUID().toString(),
            message,
            level,
            System.currentTimeMillis()
        );
        synchronized (buffer) {
            buffer.offer(log);
            if (buffer.size() >= BATCH_SIZE) {
                flushBuffer();
            }
        }
    }

    private void flushBuffer() throws IOException {
        List<LogEntry> batch = new ArrayList<>();
        synchronized (buffer) {
            while (!buffer.isEmpty() && batch.size() < BATCH_SIZE) {
                batch.add(buffer.poll());
            }
        }
        if (!batch.isEmpty()) {
            String indexName = indexPrefix + dateFormat.format(new Date());
            esClient.bulkIndex(batch, indexName);
        }
    }

    public List<LogEntry> searchLogs(
        String query,
        String level,
        Long lastTimestamp,
        int size
    ) throws IOException {
        String indexPattern = indexPrefix + "*";
        return esClient.search(indexPattern, query, level, lastTimestamp, size);
    }
}

3. 控制器

@RestController
@RequestMapping("/logs")
public class LogController {
    @Autowired
    private LogService logService;

    @PostMapping("/add")
    public String addLog(
        @RequestParam String message,
        @RequestParam String level
    ) throws IOException {
        logService.addLog(message, level);
        return "Log added";
    }

    @GetMapping("/search")
    public List<LogEntry> search(
        @RequestParam(required = false) String query,
        @RequestParam(required = false) String level,
        @RequestParam(required = false) Long lastTimestamp,
        @RequestParam(defaultValue = "10") int size
    ) throws IOException {
        return logService.searchLogs(query, level, lastTimestamp, size);
    }
}

4. 主应用类

@SpringBootApplication
public class ElasticsearchBigDataApplication {
    public static void main(String[] args) {
        SpringApplication.run(ElasticsearchBigDataApplication.class, args);
    }
}

5. 测试

前置配置
  • 集群部署
    • 3 数据节点(16GB 堆,SSD,node.attr.data: hot)。
    • 2 主节点(4GB 堆)。
    • 1 协调节点(8GB 堆)。
  • 索引模板(支持 ILM):
    curl -X PUT "localhost:9200/_template/log_template" -H 'Content-Type: application/json' -d'
    {
      "index_patterns": ["logs-*"],
      "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 1,
        "refresh_interval": "30s",
        "codec": "best_compression",
        "index.lifecycle.name": "log_policy"
      },
      "mappings": {
        "dynamic": "strict",
        "properties": {
          "message": { "type": "text" },
          "level": { "type": "keyword" },
          "timestamp": { "type": "date" }
        }
      }
    }'
    
测试 1:批量写入
  • 请求
    • POST http://localhost:8080/logs/add?message=Server started&level=INFO
    • 重复 100000 次。
  • 检查:索引 logs-2025.04.12 包含数据。
  • 分析:批量写入和缓冲区降低开销。
测试 2:高效查询
  • 请求
    • GET http://localhost:8080/logs/search?query=server&level=INFO&size=10
    • 第二次:GET http://localhost:8080/logs/search?query=server&level=INFO&lastTimestamp=1623456789&size=10
  • 响应
    [
      {
        "id": "uuid1",
        "message": "Server started",
        "level": "INFO",
        "timestamp": 1623456789
      },
      ...
    ]
    
  • 分析search_after 避免深翻页,filter 加速。
测试 3:性能测试
  • 代码
    public class BigDataPerformanceTest {
        public static void main(String[] args) throws IOException {
            LogService service = new LogService(new ElasticsearchClient());
            // 写入 1000000 条
            long start = System.currentTimeMillis();
            for (int i = 1; i <= 1000000; i++) {
                service.addLog("Server log " + i, "INFO");
            }
            long writeEnd = System.currentTimeMillis();
            // 查询
            List<LogEntry> results = service.searchLogs("server", "INFO", null, 10);
            long searchEnd = System.currentTimeMillis();
            // 深翻页
            Long lastTimestamp = results.get(results.size() - 1).getTimestamp();
            service.searchLogs("server", "INFO", lastTimestamp, 10);
            long deepSearchEnd = System.currentTimeMillis();
            System.out.println("Write time: " + (writeEnd - start) + "ms");
            System.out.println("Search time: " + (searchEnd - writeEnd) + "ms");
            System.out.println("Deep search time: " + (deepSearchEnd - searchEnd) + "ms");
        }
    }
    
  • 结果
    Write time: 120000ms
    Search time: 70ms
    Deep search time: 65ms
    
  • 分析:批量写入支持高吞吐,查询性能稳定。
测试 4:集群扩展
  • 操作
    • 添加新数据节点。
    • 检查:GET _cat/shards?v
  • 结果:分片自动重分配,负载均衡。
  • 分析:动态扩展支持数据增长。

四、进阶优化与实践经验

1. 异步写入

  • 实现
    CompletableFuture.runAsync(() -> esClient.bulkIndex(batch, indexName));
    
  • 效果:提升客户端吞吐。

2. 监控与报警

  • 工具
    • Kibana:可视化分片和节点状态。
    • GET _cat/allocation?v:检查磁盘使用。
  • 慢查询日志
    PUT logs-*/_settings
    {
      "index.search.slowlog.threshold.query.warn": "10s"
    }
    

3. Kubernetes 部署

  • 配置
    • 使用 ECK(Elastic Cloud on Kubernetes)。
    • StatefulSet 确保节点稳定。
  • 扩容
    spec:
      nodeSets:
      - name: data-hot
        count: 3
        config:
          node.attr.data: hot
    

4. 注意事项

  • 测试驱动:模拟生产数据量验证优化。
  • 冷热分离:确保硬件匹配数据访问模式。
  • 备份策略:使用 Snapshot API 保存历史数据。

五、总结

索引数据量激增要求从数据管理、性能调优和集群部署多维度应对。时间分片、ILM、批量写入和冷热分离是核心策略。本文结合 Java 实现了一个大数据量日志系统,测试验证了写入吞吐和查询效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CD27.【C++ Dev】类和对象 (18)友元和内部类

目录 1.友元 友元函数 几个特点 友元类 格式 代码示例 2.内部类(了解即可) 计算有内部类的类的大小 分析 注意:内部类不能直接定义 内部类是外部类的友元类 3.练习 承接CD21.【C Dev】类和对象(12) 流插入运算符的重载文章 1.友元 友元函数 在CD21.【C Dev】类和…

QT安装详细步骤

下载 清华源 &#xff1a; 清华源 1. 2. 3. 4.

Unity游戏多语言工具包

由于一开始的代码没有考虑多语言场景&#xff0c;导致代码中提示框和UI显示直接用了中文&#xff0c;最近开始提取代码的中文&#xff0c;提取起来太麻烦&#xff0c;所以拓展了之前的多语言包&#xff0c;降低了操作复杂度。最后把工具代码提取出来到单独项目里面&#xff0c;…

实验三 I/O地址译码

一、实验目的 掌握I/O地址译码电路的工作原理。 二、实验电路 实验电路如图1所示&#xff0c;其中74LS74为D触发器&#xff0c;可直接使用实验台上数字电路实验区的D触发器&#xff0c;74LS138为地址译码器&#xff0c; Y0&#xff1a;280H&#xff5e;287H&…

视觉语言导航(VLN):连接语言、视觉与行动的桥梁

文章目录 1. 引言&#xff1a;什么是VLN及其重要性&#xff1f;2. VLN问题定义3. 核心挑战4. 基石&#xff1a;关键数据集与模拟器5. 评估指标6. 主要方法与技术演进6.1 前CLIP时代&#xff1a;奠定基础6.2 后CLIP时代&#xff1a;视觉与语言的统一 7. 最新进展与前沿趋势 (202…

计算机网络中科大 - 第7章 网络安全(详细解析)-以及案例

目录 &#x1f6e1;️ 第8章&#xff1a;网络安全&#xff08;Network Security&#xff09;优化整合笔记&#x1f4cc; 本章学习目标 一、网络安全概念二、加密技术&#xff08;Encryption&#xff09;1. 对称加密&#xff08;Symmetric Key&#xff09;2. 公钥加密&#xff0…

XCTF-web(四)

unserialize3 需要反序列化一下&#xff1a;O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;} php_rce 题目提示rce漏洞&#xff0c;测试一下&#xff1a;?s/Index/\think\app/invokefunction&functioncall_user_func_array&vars[0]phpinfo&vars[1][]1 flag&#xff1…

在Vue项目中查询所有版本号为 1.1.9 的依赖包名 的具体方法,支持 npm/yarn/pnpm 等主流工具

以下是 在Vue项目中查询所有版本号为 1.1.9 的依赖包名 的具体方法&#xff0c;支持 npm/yarn/pnpm 等主流工具&#xff1a; 一、使用 npm 1. 直接过滤依赖树 npm ls --depth0 | grep "1.1.9"说明&#xff1a; npm ls --depth0&#xff1a;仅显示直接依赖&#xf…

若依微服务版启动小程序后端

目录标题 本地启动&#xff0c;dev对应 nacos里的 xxx-xxx-dev配置文件 本地启动&#xff0c;dev对应 nacos里的 xxx-xxx-dev配置文件

莒县第六实验小学:举行“阅读世界 丰盈自我”淘书会

4月16日&#xff0c;莒县第六实验小学校园内书香四溢、笑语盈盈&#xff0c;以“阅读世界 丰盈自我”为主题的第二十四届读书节之“淘书会”活动火热开启。全校师生齐聚一堂&#xff0c;以书会友、共享阅读之乐&#xff0c;为春日校园增添了一抹浓厚的文化气息。 活动在悠扬的诵…

国产数据库与Oracle数据库事务差异分析

数据库中的ACID是事务的基本特性&#xff0c;而在Oracle等数据库迁移到国产数据库国产中&#xff0c;可能因为不同数据库事务处理机制的不同&#xff0c;在迁移后的业务逻辑处理上存在差异。本文简要介绍了事务的ACID属性、事务的隔离级别、回滚机制和超时机制&#xff0c;并总…

C++学习记录:

今天我们来学习一门新的语言&#xff0c;也是C语言最著名的一个分支语言&#xff1a;C。 在C的学习中&#xff0c;我们主要学习的三大组成部分&#xff1a;语法、STL、数据结构。 C的介绍 C的历史可追溯至1979年&#xff0c;当时贝尔实验室的本贾尼斯特劳斯特卢普博士在面对复杂…

等离子体浸没离子注入(PIII)

一、PIII 是什么&#xff1f;基本原理和工艺 想象一下&#xff0c;你有一块金属或者硅片&#xff08;就是做芯片的那种材料&#xff09;&#xff0c;你想给它的表面“升级”&#xff0c;让它变得更硬、更耐磨&#xff0c;或者有其他特殊功能。怎么做呢&#xff1f;PIII 就像是用…

idea中提高编译速度研究

探索过程&#xff1a; 有三种情况&#xff1a; 第一种&#xff1a; idea中用eclipse编译器编译springboot项目&#xff0c;然后debug启动Application报错找不到类。 有待继续研究。 第二种&#xff1a; idea中用javac编译器编译springboot项目&#xff0c;重新构建用时&a…

静态链接part2

编译 语义分析 由语义分析器完成&#xff0c;这个步骤只是完成了对表达式的语法层面的分析&#xff0c;它并不了解这个语句是否真的有意义&#xff08;例如在C语言中两个指针做乘法运算&#xff0c;这个语句在语法上是合法的&#xff0c;但是没有什么意义&#xff1b;还有同样…

Vue3+Vite+TypeScript+Element Plus开发-17.Tags-组件构建

系列文档目录 Vue3ViteTypeScript安装 Element Plus安装与配置 主页设计与router配置 静态菜单设计 Pinia引入 Header响应式菜单缩展 Mockjs引用与Axios封装 登录设计 登录成功跳转主页 多用户动态加载菜单 Pinia持久化 动态路由 -动态增加路由 动态路由-动态删除…

3D语义地图中的全局路径规划!iPPD:基于3D语义地图的指令引导路径规划视觉语言导航

作者&#xff1a; Zehao Wang, Mingxiao Li, Minye Wu, Marie-Francine Moens, Tinne Tuytelaars 单位&#xff1a;鲁汶大学电气工程系&#xff0c;鲁汶大学计算机科学系 论文标题&#xff1a; Instruction-guided path planning with 3D semantic maps for vision-language …

ShellScript脚本编程

语法基础 脚本结构 我们先从这个小demo程序来窥探一下我们shell脚本的程序结构 #!/bin/bash# 注释信息echo_str"hello world"test(){echo $echo_str }test echo_str 首先我们可以通过文本编辑器(在这里我们使用linux自带文本编辑神器vim)&#xff0c;新建一个文件…

【HarmonyOS 5】敏感信息本地存储详解

【HarmonyOS 5】敏感信息本地存储详解 前言 鸿蒙其实自身已经通过多层次的安全机制&#xff0c;确保用户敏感信息本地存储安全。不过再此基础上&#xff0c;用户敏感信息一般三方应用还需要再进行加密存储。 本文章会从鸿蒙自身的安全机制进行展开&#xff0c;最后再说明本地…

探索鸿蒙沉浸式:打造无界交互体验

一、鸿蒙沉浸式简介 在鸿蒙系统中&#xff0c;沉浸式是一种极具特色的设计理念&#xff0c;它致力于让用户在使用应用时能够全身心投入到内容本身&#xff0c;而尽可能减少被系统界面元素的干扰。通常来说&#xff0c;就是将应用的内容区巧妙地延伸到状态栏和导航栏所在的界面…