ElasticSearch深度分页解决方案

文章目录

    • 概要
    • ElasticSearch介绍
    • es分页方法
        • es分页性能对比表
        • 方案对比
    • From/Size参数
    • 深度分页问题
    • Scroll
      • #性能对比
        • 向前翻页
    • 总结
    • 个人思考

概要

好久没更新文章了,最近研究了一下es的深分页解决方案。和大家分享一下,祝大家国庆节快乐。

ElasticSearch介绍

Elasticsearch 是一个分布式、可扩展、实时的搜索与数据分析引擎,在使用过程中,有一些典型的使用场景,比如分页、遍历等。

在使用关系型数据库中,我们被告知要注意甚至被明确禁止使用深度分页,同理,在 Elasticsearch 中,也应该尽量避免使用深度分页。

这篇文章主要介绍 Elasticsearch 中分页相关内容!

es分页方法

  • From/Size参数
  • Scroll
  • Scroll Scan
  • Sliced Scroll
  • Search After
es分页性能对比表
分页方式1~1049000~4901099000~999010
from + size8ms30ms117ms
Scroll7ms66ms36ms
Search After8ms8ms7ms
方案对比
方案原理优点缺点使用场景
from + size类似 msql的 limit 0,100; limit from,size灵活性好,实现简单,适合浅分页无法实现深度分页问题,当查询数量超过10000就会报错top10000以内的查询
Scroll首次查询会在内存中保存一个历史快照以及游标(scroll_id),记录当前消息查询的终止位置,下次查询的时候将基于游标进行消费(不管while语句循环多少次,scrollid在设置的时效内,使用的是同一个),不具备实时性,一般是用于大量数据导出。适合深分页无法反应数据的实时性(快照版本),维护成本高,需要维护一个 scroll_id最适合离线场景,海量数据的导出(比如笔者刚遇到的将es中20w的数据导入到excel),需要查询海量结果集的数据
Search Afterstep1:在查询第1页的时候,设置全局唯一性的字段进行组合排序;step2:查询数据之后,取出最后一笔数据的sort值,传到search_after进行查询;step3:基于上一笔的sort值,查询排在它之后的数据,以此来实现分页不能够随机跳转分页,只能是一页一页的向后翻(当有新数据进来,也能实时查询到),并且需要至少指定一个唯一不重复字段来排序(一般是_id和时间字段)海量数据的实时分页性能最好,适合深分页,能够反映数据的实时变更

From/Size参数

在ES中,分页查询默认返回最顶端的10条匹配hits。

如果需要分页,需要使用from和size参数。

  • from参数定义了需要跳过的hits数,默认为0;

  • size参数定义了需要返回的hits数目的最大值。

一个基本的ES查询语句是这样的:

	POST /my_index/my_type/_search{"query": { "match_all": {}},"from": 100,"size":  10}

上面的查询表示从搜索结果中取第100条开始的10条数据。

** 那么,这个查询语句在ES集群内部是怎么执行的呢?**

在ES中,搜索一般包括两个阶段,query 和 fetch 阶段,可以简单的理解,query 阶段确定要取哪些doc,fetch 阶段取出具体的 doc。

Query阶段

图片
如上图所示,描述了一次搜索请求的 query 阶段:·
在这里插入图片描述

Client 发送一次搜索请求,node1 接收到请求,然后,node1 创建一个大小为from + size的优先级队列用来存结果,我们管 node1 叫 coordinating node。
coordinating node将请求广播到涉及到的 shards,每个 shard 在内部执行搜索请求,然后,将结果存到内部的大小同样为from + size 的优先级队列里,可以把优先级队列理解为一个包含top N结果的列表。
每个 shard 把暂存在自身优先级队列里的数据返回给 coordinating node,coordinating node 拿到各个 shards 返回的结果后对结果进行一次合并,产生一个全局的优先级队列,存到自身的优先级队列里。
在上面的例子中,coordinating node 拿到(from + size) * 6条数据,然后合并并排序后选择前面的from + size条数据存到优先级队列,以便 fetch 阶段使用。

另外,各个分片返回给 coordinating node 的数据用于选出前from + size条数据,所以,只需要返回唯一标记 doc 的_id以及用于排序的_score即可,这样也可以保证返回的数据量足够小。

coordinating node 计算好自己的优先级队列后,query 阶段结束,进入 fetch 阶段。


Fetch阶段


query 阶段知道了要取哪些数据,但是并没有取具体的数据,这就是 fetch 阶段要做的。
在这里插入图片描述
上图展示了 fetch 过程:

coordinating node 发送 GET 请求到相关shards。
shard 根据 doc 的_id取到数据详情,然后返回给 coordinating node。
coordinating node 返回数据给 Client。
coordinating node 的优先级队列里有from + size 个_doc _id,但是,在 fetch 阶段,并不需要取回所有数据,在上面的例子中,前100条数据是不需要取的,只需要取优先级队列里的第101到110条数据即可。

需要取的数据可能在不同分片,也可能在同一分片,coordinating node 使用 「multi-get」 来避免多次去同一分片取数据,从而提高性能。

「这种方式请求深度分页是有问题的:」

我们可以假设在一个有 5 个主分片的索引中搜索。当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点 ,协调节点对 50 个结果排序得到全部结果的前 10 个。

现在假设我们请求第 1000 页—结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。

「对结果排序的成本随分页的深度成指数上升。」

「注意1:」

size的大小不能超过index.max_result_window这个参数的设置,默认为10000。

如果搜索size大于10000,需要设置index.max_result_window参数

PUT _settings
{"index": {"max_result_window": "10000000"}
}  

[^1] _doc将在未来的版本移除,详见:
https://www.elastic.co/cn/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0
https://elasticsearch.cn/article/158
图片

深度分页问题

Elasticsearch 的From/Size方式提供了分页的功能,同时,也有相应的限制。

举个例子,一个索引,有10亿数据,分10个 shards,然后,一个搜索请求,from=1000000,size=100,这时候,会带来严重的性能问题:CPU,内存,IO,网络带宽。

在 query 阶段,每个shards需要返回 1000100 条数据给 coordinating node,而 coordinating node 需要接收10 * 1000,100 条数据,即使每条数据只有 _doc _id 和 _score,这数据量也很大了?

「在另一方面,我们意识到,这种深度分页的请求并不合理,因为我们是很少人为的看很后面的请求的,在很多的业务场景中,都直接限制分页,比如只能看前100页。」

比如,有1千万粉丝的微信大V,要给所有粉丝群发消息,或者给某省粉丝群发,这时候就需要取得所有符合条件的粉丝,而最容易想到的就是利用 from + size 来实现,不过,这个是不现实的,这时,可以采用 Elasticsearch 提供的其他方式来实现遍历。

深度分页问题大致可以分为两类:

「随机深度分页:随机跳转页面」
「滚动深度分页:只能一页一页往下查询」
「下面介绍几个官方提供的深度分页方法」

Scroll


Scroll遍历数据


我们可以把scroll理解为关系型数据库里的cursor,因此,scroll并不适合用来做实时搜索,而更适合用于后台批处理任务,比如群发。

这个分页的用法,「不是为了实时查询数据」,而是为了「一次性查询大量的数据(甚至是全部的数据」)。

因为这个scroll相当于维护了一份当前索引段的快照信息,这个快照信息是你执行这个scroll查询时的快照。在这个查询后的任何新索引进来的数据,都不会在这个快照中查询到。

但是它相对于from和size,不是查询所有数据然后剔除不要的部分,而是记录一个读取的位置,保证下一次快速继续读取。

不考虑排序的时候,可以结合SearchType.SCAN使用。

scroll可以分为初始化和遍历两部,初始化时将「所有符合搜索条件的搜索结果缓存起来(注意,这里只是缓存的doc_id,而并不是真的缓存了所有的文档数据,取数据是在fetch阶段完成的)」,可以想象成快照。

在遍历时,从这个快照里取数据,也就是说,在初始化后,对索引插入、删除、更新数据都不会影响遍历结果。

「基本使用」

POST /twitter/tweet/_search?scroll=1m
{"size": 100,"query": {"match" : {"title" : "elasticsearch"}}
}

初始化指明 index 和 type,然后,加上参数 scroll,表示暂存搜索结果的时间,其它就像一个普通的search请求一样。

会返回一个_scroll_id,_scroll_id用来下次取数据用。

「遍历」

POST /_search?scroll=1m
{"scroll_id":"XXXXXXXXXXXXXXXXXXXXXXX I am scroll id XXXXXXXXXXXXXXX"
}

这里的scroll_id即 上一次遍历取回的_scroll_id或者是初始化返回的_scroll_id,同样的,需要带 scroll 参数。

重复这一步骤,直到返回的数据为空,即遍历完成。

「注意,每次都要传参数 scroll,刷新搜索结果的缓存时间」。另外,「不需要指定 index 和 type」。

设置scroll的时候,需要使搜索结果缓存到下一次遍历完成,「同时,也不能太长,毕竟空间有限。」

「优缺点」

缺点:

「scroll_id会占用大量的资源(特别是排序的请求)」
同样的,scroll后接超时时间,频繁的发起scroll请求,会出现一些列问题。
「是生成的历史快照,对于数据的变更不会反映到快照上。」
「优点:」

适用于非实时处理大量数据的情况,比如要进行数据迁移或者索引变更之类的。

Scroll Scan
ES提供了scroll scan方式进一步提高遍历性能,但是scroll scan不支持排序,因此scroll scan适合不需要排序的场景

「基本使用」

Scroll Scan 的遍历与普通 Scroll 一样,初始化存在一点差别。

POST /my_index/my_type/_search?search_type=scan&scroll=1m&size=50
{"query": { "match_all": {}}
}

需要指明参数:

search_type:赋值为scan,表示采用 Scroll Scan 的方式遍历,同时告诉 Elasticsearch 搜索结果不需要排序。
scroll:同上,传时间。
size:与普通的 size 不同,这个 size 表示的是每个 shard 返回的 size 数,最终结果最大为 number_of_shards * size。
「Scroll Scan与Scroll的区别」

Scroll-Scan结果「没有排序」,按index顺序返回,没有排序,可以提高取数据性能。
初始化时只返回 _scroll_id,没有具体的hits结果
size控制的是每个分片的返回的数据量,而不是整个请求返回的数据量。
Sliced Scroll
如果你数据量很大,用Scroll遍历数据那确实是接受不了,现在Scroll接口可以并发来进行数据遍历了。

每个Scroll请求,可以分成多个Slice请求,可以理解为切片,各Slice独立并行,比用Scroll遍历要快很多倍。

POST /index/type/_search?scroll=1m
{"query": { "match_all": {}},"slice": {"id": 0,"max": 5}   
}POST ip:port/index/type/_search?scroll=1m
{"query": { "match_all": {}},"slice": {"id": 1,"max": 5}   
}

上边的示例可以单独请求两块数据,最终五块数据合并的结果与直接scroll scan相同。

其中max是分块数,id是第几块。


官方文档中建议max的值不要超过shard的数量,否则可能会导致内存爆炸。


Search After
Search_after是 ES 5 新引入的一种分页查询机制,其原理几乎就是和scroll一样,因此代码也几乎是一样的。

「基本使用:」

第一步:

POST twitter/_search
{"size": 10,"query": {"match" : {"title" : "es"}},"sort": [{"date": "asc"},{"_id": "desc"}]
}

返回出的结果信息 :

{"took" : 29,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 5,"relation" : "eq"},"max_score" : null,"hits" : [{...},"sort" : [...]},{...},"sort" : [124648691,"624812"]}]}}

上面的请求会为每一个文档返回一个包含sort排序值的数组。

这些sort排序值可以被用于search_after参数里以便抓取下一页的数据。

比如,我们可以使用最后的一个文档的sort排序值,将它传递给search_after参数:

GET twitter/_search
{"size": 10,"query": {"match" : {"title" : "es"}},"search_after": [124648691, "624812"],"sort": [{"date": "asc"},{"_id": "desc"}]
}

若我们想接着上次读取的结果进行读取下一页数据,第二次查询在第一次查询时的语句基础上添加search_after,并指明从哪个数据后开始读取。

「基本原理」

es维护一个实时游标,它以上一次查询的最后一条记录为游标,方便对下一页的查询,它是一个无状态的查询,因此每次查询的都是最新的数据。

由于它采用记录作为游标,因此「SearchAfter要求doc中至少有一条全局唯一变量(每个文档具有一个唯一值的字段应该用作排序规范)」

「优缺点」

「优点:」

无状态查询,可以防止在查询过程中,数据的变更无法及时反映到查询中。
不需要维护scroll_id,不需要维护快照,因此可以避免消耗大量的资源。
「缺点:」

由于无状态查询,因此在查询期间的变更可能会导致跨页面的不一值。
排序顺序可能会在执行期间发生变化,具体取决于索引的更新和删除。
至少需要制定一个唯一的不重复字段来排序。
它不适用于大幅度跳页查询,或者全量导出,对第N页的跳转查询相当于对es不断重复的执行N次search after,而全量导出则是在短时间内执行大量的重复查询。
SEARCH_AFTER不是自由跳转到任意页面的解决方案,而是并行滚动多个查询的解决方案。

总结
分页方式 性能 优点 缺点 场景
from + size 低 灵活性好,实现简单 深度分页问题 数据量比较小,能容忍深度分页问题
scroll 中 解决了深度分页问题 无法反应数据的实时性(快照版本)维护成本高,需要维护一个 scroll_id 海量数据的导出需要查询海量结果集的数据
search_after 高 性能最好不存在深度分页问题能够反映数据的实时变更 实现复杂,需要有一个全局唯一的字段连续分页的实现会比较复杂,因为每一次查询都需要上次查询的结果,它不适用于大幅度跳页查询 海量数据的分页
ES7版本变更
参照:https://www.elastic.co/guide/en/elasticsearch/reference/master/paginate-search-results.html#scroll-search-results

在7.*版本中,ES官方不再推荐使用Scroll方法来进行深分页,而是推荐使用带PIT的search_after来进行查询;

从7.*版本开始,您可以使用SEARCH_AFTER参数通过上一页中的一组排序值检索下一页命中。

使用SEARCH_AFTER需要多个具有相同查询和排序值的搜索请求。

如果这些请求之间发生刷新,则结果的顺序可能会更改,从而导致页面之间的结果不一致。

为防止出现这种情况,您可以创建一个时间点(PIT)来在搜索过程中保留当前索引状态。

POST /my-index-000001/_pit?keep_alive=1m
返回一个PIT ID:
{"id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA=="
}

在搜索请求中指定PIT:

GET /_search
{"size": 10000,"query": {"match" : {"user.id" : "elkbee"}},"pit": {"id":  "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", "keep_alive": "1m"},"sort": [ {"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos", "numeric_type" : "date_nanos" }}]
}

#性能对比

分别分页获取1 - 10,49000 - 49010,99000 - 99010范围各10条数据(前提10w条),性能大致是这样:
图片

向前翻页
  • 对于向前翻页,ES中没有相应API,但是根据官方说法(https://github.com/elastic/elasticsearch/issues/29449),ES中的向前翻页问题可以通过翻转排序方式来实现即:

  • 对于某一页,正序search_after该页的最后一条数据id为下一页,则逆序search_after该页的第一条数据id则为上一页。
    国内论坛上,有人使用缓存来解决上一页的问题

总结

  1. 如果数据量小(from+size在10000条内),或者只关注结果集的TopN数据,可以使用from/size 分页,简单粗暴
  2. 数据量大,深度翻页,后台批处理任务(数据迁移)之类的任务,使用 scroll 方式
  3. 数据量大,深度翻页,用户实时、高并发查询需求,使用 search after 方式

个人思考

Scroll和search_after原理基本相同,他们都采用了游标的方式来进行深分页。

这种方式虽然能够一定程度上解决深分页问题。但是,它们并不是深分页问题的终极解决方案,深分页问题 ** 必须避免!! **。

对于Scroll,无可避免的要维护scroll_id和历史快照,并且,还必须保证scroll_id的存活时间,这对服务器是一个巨大的负荷。

对于Search_After,如果允许用户大幅度跳转页面,会导致短时间内频繁的搜索动作,这样的效率非常低下,这也会增加服务器的负荷,同时,在查询过程中,索引的增删改会导致查询数据不一致或者排序变化,造成结果不准确。

Search_After本身就是一种业务折中方案,它不允许指定跳转到页面,而只提供下一页的功能。

Scroll默认你会在后续将所有符合条件的数据都取出来,所以,它只是搜索到了所有的符合条件的doc_id(这也是为什么官方推荐用doc_id进行排序,因为本身缓存的就是doc_id,如果用其他字段排序会增加查询量),并将它们排序后保存在协调节点(coordinate node),但是并没有将所有数据进行fetch,而是每次scroll,读取size个文档,并返回此次读取的最后一个文档以及上下文状态,用以告知下一次需要从哪个shard的哪个文档之后开始读取。

这也是为什么官方不推荐scroll用来给用户进行实时的分页查询,而是适合于大批量的拉取数据,因为它从设计上就不是为了实时读取数据而设计的。

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

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

相关文章

在MyBatisPlus中添加分页插件

开发过程中,数据量大的时候,查询效率会有所下降,这时,我们往往会使用分页。 具体操作入下: 1、添加分页插件: package com.zhang.config;import com.baomidou.mybatisplus.extension.plugins.Pagination…

安防监控/视频汇聚平台EasyCVR云端录像不展示是什么原因?该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、…

vue + openlayer 按路径移动

示例 创建一个方形的规矩&#xff0c;并让点按轨迹移动。效果如下: 源代码 <template><div><div id"map" class"map"></div><button id"start-animation" ref"startButton">Start Animation</bu…

玩转数据-大数据-Flink SQL 中的时间属性

一、说明 时间属性是大数据中的一个重要方面&#xff0c;像窗口&#xff08;在 Table API 和 SQL &#xff09;这种基于时间的操作&#xff0c;需要有时间信息。我们可以通过时间属性来更加灵活高效地处理数据&#xff0c;下面我们通过处理时间和事件时间来探讨一下Flink SQL …

排序篇(二)----选择排序

排序篇(二)----选择排序 1.直接选择排序 基本思想&#xff1a; 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 直接选择排序: ​ 在元素集合array[i]–array[…

Spring修炼之路(1)基础入门

一、简介 1.1Spring概述 Spring框架是一个轻量级的Java开发框架&#xff0c;它提供了一系列底层容器和基础设施&#xff0c;并可以和大量常用的开源框架无缝集成&#xff0c;可以说是开发Java EE应用程序的必备。Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器&…

虾皮商品详情数据接口

虾皮商品详情数据接口可以提供众多API读取内容&#xff0c;可传输大量数据&#xff0c;数据更新速度尤其快&#xff0c;保证了跨境电商接口服务数据的及时性及准确性&#xff1b;安全性强&#xff1a;使用SSL及虾皮网自主的安全技术&#xff0c;确保了跨境电商接口服务数据的安…

【2023保研】双非上岸东南网安

个人情况 学校&#xff1a;henu 专业&#xff1a;信息安全 排名&#xff1a;1/66 英语&#xff1a;六级500 竞赛&#xff1a;蓝桥杯PB国一&#xff0c;ISCC国一&#xff0c;密码数学挑战赛国三&#xff0c;还有其他一些省级水奖 论文&#xff1a;一篇EI在投&#xff08;三作通…

[Qt]QListView 重绘实例之二:列表项覆盖的问题处理

0 环境 Windows 11Qt 5.15.2 MinGW x64 1 系列文章 简介&#xff1a;本系列文章&#xff0c;是以纯代码方式实现 Qt 控件的重构&#xff0c;尽量不使用 Qss 方式。 《[Qt]QListView 重绘实例之一&#xff1a;背景重绘》 《[Qt]QListView 重绘实例之二&#xff1a;列表项覆…

elementui引入弹出框报错:this.$alert is not defined 解决方案

1.按需引入文件element.js 注意&#xff1a;引入Message&#xff0c;MessageBox两个组件就行&#xff0c;alert包括在MessageBox里面了。 之前我引入了Alert组件&#xff0c;发现不行 2.在vue的prototype里注册伪名字 3.组件里直接调用就行了 4.实现效果 我发现elementui调用…

【C++进阶】:C++11

C11 一.统一列表的初始化1.{}初始化2.initializer_list 二.声明1.decltype2.nullptr 三.右值引用和移动语义1.左值和右值1.转义语句2.完美转发 四.可变参数模板1.基本概念2.STL里emplace类接口 五.lambda表达式六.新的类功能 一.统一列表的初始化 1.{}初始化 在C98中&#xf…

图像处理: 马赛克艺术

马赛克 第一章 马赛克的历史渊源 1.1 马赛克 艺术中的一种表面装饰&#xff0c;由紧密排列的、通常颜色各异的小块材料&#xff08;如石头、矿物、玻璃、瓷砖或贝壳&#xff09;组成。与镶嵌不同的是&#xff0c;镶嵌是将要应用的部件放置在已挖空以容纳设计的表面中&#xff0…

【教学类-35-03】学号+姓名+班级(小3班)学号字帖(A4竖版2份)

图片展示: 背景需求: 本周排到小3班&#xff0c;还没有来得及设计小班主题活动书的内容&#xff0c;于是就把小2班的学号字帖微调一下&#xff0c;做一份竖版2份的学号字帖。 让幼儿熟悉自己的学号&#xff0c;让我也熟悉幼儿的名字和学号 材料准备&#xff1a; 描字写&#…

关于RabbitMQ你了解多少?

关于RabbitMQ你了解多少&#xff1f; 文章目录 关于RabbitMQ你了解多少&#xff1f;基础篇同步和异步MQ技术选型介绍和安装数据隔离SpringAMQP快速入门Work queues交换机Fanout交换机Direct交换机Topic交换机 声明队列和交换机MQ消息转换器 高级篇消息可靠性问题发送者的可靠性…

妙不可言的Python之旅----(一)

初识Python python的起源 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum吉多 范罗苏姆&#xff08;龟叔&#xff09;决心开发一个新的解释程序&#xff08;Python雏形&#xff09; 1991年&#xff0c;第一个Python解释器诞生 Python这个名字&#xff…

Golang中的包和模块设计

Go&#xff0c;也被称为Golang&#xff0c;是一种静态类型、编译型语言&#xff0c;因其简洁性和对并发编程的强大支持而受到开发者们的喜爱。Go编程的一个关键方面是其包和模块系统&#xff0c;它允许创建可重用、可维护和高效的代码。本博客文章将深入探讨在Go中设计包和模块…

Servlet操作与用法(保姆式教学)

Servlet介绍 什么是servlet Servlet&#xff08;Servlet Applet的缩写&#xff0c;全称 Java Servlet&#xff09;&#xff1a;适用于Java编写的服务器程序&#xff0c;其主要功能是在于交互式的浏览和修改数据&#xff0c;生成动态Web内容。狭义的Servlet是指Java语言实现的…

MySQL学习笔记27

MySQL主从复制的核心思路&#xff1a; 1、slave必须安装相同版本的mysql数据库软件。 2、master端必须开启二进制日志&#xff0c;slave端必须开启relay log 日志。 3、master主服务器和slave从服务器的server-id号不能一致。 4、slave端配置向master端来同步数据。 master…

云安全之访问控制的常见攻击及防御

访问控制攻击概述 访问控制漏洞即应用程序允许攻击者执行或者访问某种攻击者不具备相应权限的功能或资源。 常见的访问控制可以分为垂直访问控制、水平访问控制及多阶段访问控制 (上下文相关访问控制)&#xff0c;与其相应的访问控制漏洞为也垂直越权漏洞(普通用户可以访问或…

【QT】使用toBase64方法将.txt文件的明文变为非明文(类似加密)

目录 0.环境 1.背景 2.详细代码 2.1 .h主要代码 2.2 .cpp主要代码&#xff0c;主要实现上述的四个方法 0.环境 windows 11 64位 Qt Creator 4.13.1 1.背景 项目需求&#xff1a;我们项目中有配置文件&#xff08;类似.txt&#xff0c;但不是这个格式&#xff0c;本文以…