3、Redis Stack扩展功能

文章目录

  • 一、了解Redis产品
  • 二、申请RedisCloud实例
  • 三、Redis Stack体验
    • 1、RedisStack有哪些扩展?
    • 2、Redis JSON
      • 1、Redis JSON是什么
      • 2、Redis JSON有什么用
      • 3、Redis JSON的优势
    • 3、Search And Query
      • 1、传统Scan搜索
      • 2、Search And Query搜索
    • 4、Bloom Filter
      • 1、布隆过滤器是什么
      • 2、Guava的布隆过滤器示例
      • 3、Redis的BloomFilter使用示例
    • 5、Cuckoo Filter
      • 1、CuckooFilter是什么?
      • 2、CuckooFilter使用示例
  • 四、Redis Stack补充
    • 1、手动安装Redis扩展模块
    • 2、Java客户端调用扩展模块

一、了解Redis产品

目前,在Redis的官网上,可以看到Redis已经包含了多个产品。

在这里插入图片描述

其中,Redis Cloud是Redis的云服务,Redis Insight是Redis官方推出的图形化客户端。解决了Redis客户端群龙无首的囧境。

而Redis本身,也已经划分成了几个版本。Redis OSS就是我们之前用的Redis。 Redis Stack可以理解为是Redis加上一系列的扩展产品。Redis Enterprise是Redis的企业版。

这次我们就一起来体验一下Redis Stack的扩展功能。

二、申请RedisCloud实例

Redis Stack可以在我们之前安装的Redis服务上,自行下载安装新的扩展模块。在目前阶段,在RedisCloud上可以申请一个免费的RedisStack实例,快速体验Redis Stack的功能。

从Redis官网的右上角,就有Redis Cloud的登录链接。目前Redis Cloud提供了多种第三方登录的方式,可以选择合适的方式注册账号。
在这里插入图片描述

注册登录后,Redis Cloud就会分配一个免费的Redis实例。提供了Redis Stack功能支持。

在这里插入图片描述

接下来使用命令行,就可以连上这个Redis实例。

这个实例空间非常有限,而且无法长期使用。如果有更多需求,可以去了解一下付费版本。基础付费5美元/月

三、Redis Stack体验

1、RedisStack有哪些扩展?

目前Redis的官网上,单独构建了Redis的指令页面。在这个页面可以直接搜索相关的功能。

在这里插入图片描述

另外, 在redis-cli客户端也可以使用module list指令查看当前Redis服务中有哪些扩展。

Redis Stack的这些扩展功能,也可以手动添加到自己的Redis服务中。但是通常并不是必须的。我们可以使用Redis Cloud上的实例先完整体验一下,再考虑要不要使用这些扩展。

接下来找几个比较常见的扩展模块,体验一下。

2、Redis JSON

1、Redis JSON是什么

RedisJSON是Redis的一个扩展模块,它提供了对JSON数据的原生支持。通过RedisJSON,我们可以将JSON数据直接存储在Redis中,并利用丰富的命令集进行高效的查询和操作。RedisJSON不仅简化了数据处理的流程,还大幅提升了处理JSON数据的性能。

2、Redis JSON有什么用

Redis JSON的常用指令,在官网的Commands页面搜索JSON组就能看到

在Redis服务端,这些扩展指令并没有严格分组,而是都放在一个叫做module的组

redis-17998.c295.ap-southeast-1-1.ec2.redns.redis-cloud.com:17998> help JSON.SETJSON.SET (null)summary: (null)group: module

Redis JSON模块为Redis添加了JSON数据类型的支持,并且对JSON数据提供了快速进行增、删、改、查的操作。

-- 设置一个JSON数据
JSON.SET user $ '{"name":"loulan","age":18}'
## key是user,value就是一个JSON数据。其中$表示JSON数据的根节点。
-- 查询JSON数据
JSON.GET user
-- 查询JSON对象的name属性
JSON.GET user $.name
-- 查看数据类型
JSON.TYPE user    -- object
JSON.TYPE user $.name   --- string
JSON.TYPE user $.age    --- integer
--修改JSON数据 年龄加2
JSON.NUMINCRBY user $.age 2
-- 添加新的字段
JSON.SET user $.address '{"city": "Changsha", "country": "China"}' NX
## NX 表示只有当address字段不存在的时候才进行设置。
-- 在JSON数组中添加元素
JSON.SET user $.hobbies '["reading"]'
JSON.ARRAPPEND user $.hobbies '"swimming"'
-- 查看JSON对象中key的个数
JSON.OBJLEN user $.address-- 查看user对象的所有key
JSON.OBJKEYS user-- 删除JSON中的key
JSON.DEL user $.address

3、Redis JSON的优势

JSON是现代应用程序中经常用到的一种数据类型。很多时候,就算没有Redis JSON插件,我们也会采用JSON格式来缓存复杂的数据类型。比如在分布式场景下做用户登录功能,我们就可以将用户信息以JSON字符串的形式保存到Redis中,来代替单体应用中的Session,从而实现统一的登录状态管理。这些数据使用Redis JSON插件来管理,就显得顺理成章了。

并且Redis JSON插件相比用string管理这种JSON数据,还能带来一些很明显的优势。

  • Redis JSON存储数据的性能更高。Redis JSON底层其实是以一种高效的二进制的格式存储。相比简单的文本格式,二进制格式进行JOSN格式读写的性能更高,也更节省内存。根据官网的性能测试报告,使用Redis JSON读写JSON数据,性能已经能够媲美MongoDB以及ElasticSearch等传统NoSQL数据库。
  • Redis JSON使用树状结构来存储JSON。这种存储方式可以快速访问子元素。与传统的文本存储方案相比,树状存储结构能够更高效的执行查询操作。
  • 与Redis生态集成度高。作为Redis的扩展模块,Redis JSON和Redis的其他功能和工具无缝集成。这意味着开发者可以继续使用TTL、Redis事务、发布/订阅、Lua脚本等功能。

3、Search And Query

当Redis中存储的数据比较多时,搜索Redis中的数据是一件比较麻烦的事情。通常使用的 keys * 这样的指令,在生产环境一般都是直接禁用的,因为这样会产生严重的线程阻塞,影响其他的读写操作。

如何快速搜索Redis中的数据(主要是key)呢? Redis中原生提供了Scan指令,另外在Redis Stack中也增加了Search And Query模块。

1、传统Scan搜索

Scan指令的官方介绍:https://redis.io/docs/latest/commands/scan/

Scan指令的基础思想就是每次只返回想要查询的一部分结果数据,然后通过迭代的方式,逐步返回完整数据。

scan指令的基础使用方式:

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

这几个核心参数介绍如下:

  • cursor: 游标。代表每次迭代返回的偏移量。通常一次查询,cursor从0开始,然后scan指令会返回下一次迭代的起始偏移量。用户可以用这个返回值作为cursor,继续迭代下一批。直到cursor返回0,表示所有数据都过滤完成了。
  • pattern:匹配字符串。用来匹配要查询的key。 例如 user* 表示以user开头的字符串。
  • count:数字,表示每次迭代多少条数据。
  • type是key的类型,比如可以指定string ,set,zset等。

另外,针对不同key类型,还有一些不同的指令。 比如 SSCAN针对Set类型。HSCAN针对HASH类型。 ZSCAN针对ZSet类型。

简单示例如下:

-- 准备数据
eval 'for i = 1,30,1 do redis.call("SET","k"..tostring(i),"v"..tostring(i)) end' 0--简单按照cursor过滤所有key。
scan 0
1) 18      ## 下一次迭代的cursor
....
scan 18
1) 21
....
scan 21
1) 0       ## 返回0表述所有数据过滤完成
....-- 按照patern过滤 查询所有k开头的key
scan 0 MATCH k*
1) 18
...
scan 18 MATCH k*
1) 21
...
scan 21 MATCH k* 
1) 0-- 设置迭代次数
scan 0 MATCH k* count 20
1) 21
...
scan 21 MATCH k* count 20
1) 0

2、Search And Query搜索

传统的SCAN搜索方式,只能简单的过滤Key。如果想要做一些复杂的搜索,就力不从心了。

比如在电商场景中,我们通常会用Redis来缓存商品信息,但是如果要做按品牌、型号、价格等等各种条件过滤商品的场景,Redis就不够用了。以往我们会选择将商品数据导入到MongoDB或者ElasticSearch这样的搜索引擎进行复杂过滤。

在这里插入图片描述

而Redis提供了RedisSearch插件,基本就可以认为是ElasticSearch这类搜索引擎的平替。大部分ES能够实现的搜索功能,在Redis里就能直接进行。这样就极大的减少了数据迁移带来的麻烦。

既然要做搜索,那就需要有能够支持搜索的数据结构。 Redis的哪些数据结构能够支持结构化查询呢?只有HASH和JSON。

--清空数据
flushall
-- 创建一个产品的索引
FT.CREATE productIndex ON JSON SCHEMA $.name AS name TEXT $.price AS price NUMERIC
## 索引为productIndex. 
## ON JSON 表示 这个索引会基于JSON数据构建,需要RedisJSON模块的支持。默认是ON HASH 表示检索所有HASH格式的数据
## SCHEMA表示根据哪些字段建立索引。  字段名 AS 索引字段名 数据类型  这样的组合。如果是JSON格式,字段名用$. 路径表示-- 模拟一批产品信息
JSON.SET phone:1 $ '{"id":1,"name":"HUAWEI 1","description":"HUAWEI PHONE 1","price":1999}'
JSON.SET phone:2 $ '{"id":2,"name":"HUAWEI 2","description":"HUAWEI PHONE 2","price":2999}'
JSON.SET phone:3 $ '{"id":3,"name":"HUAWEI 3","description":"HUAWEI PHONE 3","price":3999}'
JSON.SET phone:4 $ '{"id":4,"name":"HUAWEI 4","description":"HUAWEI PHONE 4","price":4999}'
JSON.SET phone:5 $ '{"id":5,"name":"HUAWEI 5","description":"HUAWEI PHONE 5","price":5999}'
JSON.SET phone:6 $ '{"id":6,"name":"HUAWEI 6","description":"HUAWEI PHONE 6","price":6999}'
JSON.SET phone:7 $ '{"id":7,"name":"HUAWEI 7","description":"HUAWEI PHONE 7","price":7999}'
JSON.SET phone:8 $ '{"id":8,"name":"HUAWEI 8","description":"HUAWEI PHONE 8","price":8999}'
JSON.SET phone:9 $ '{"id":9,"name":"HUAWEI 9","description":"HUAWEI PHONE 9","price":9999}'
JSON.SET phone:10 $ '{"id":10,"name":"HUAWEI 10","description":"HUAWEI PHONE 10","price":19999}'## 如果是ON HASH ,可以直接通过索引添加数据
## FT.ADD productIndex 'product:1'  1.0 FIELDS "id" 1 "name" "HUAWEI1" "description" "HUAWEI PHONE 1" "PRICE" 3999
## 数据的key 是producr:1 
## FIELDS 数据。 按照 key value 的格式组织 -- 查看索引状态
FT.INFO productIndex-- 搜索产品 
## 搜索条件: name包含 HUAWEI, price在1000到5000之间。返回id和name
FT.SEARCH productIndex "@name:HUAWEI @price:[1000 5000]" RETURN 2 id name
## 查询条件构建,参见官网 https://redis.io/docs/latest/develop/interact/search-and-query/query/

4、Bloom Filter

1、布隆过滤器是什么

一句话解释:一种快速检索一个元素是否在一个海量集合中的算法。

比如现在有一个签到活动,要求每个用户只能签到一次,重复签到无效。这种常见的需求怎么做?如果不考虑数量级,那么非常简单。把所有签到的用户ID存到一个集合里。签到前到集合里检查一下用户ID有没有就可以了。

但是,如果你要面对的是淘宝的海量用户信息呢?这个集合得要多大?在一个海量集合里检索一个数据,是不是很慢?这就需要一个更节省空间同时更高效的算法,能够在海量数据集合中快速判断一个元素存不存在。这就可以用布隆过滤器。

布隆过滤器的使用场景非常多,最典型的应用是作为缓存数据的前端过滤缓存。快速比如,在淘宝这种海量用户的登录场景,也可以用布隆过滤器,快速判断用户输入的用户名是不是存在。如果用户名不存在,那么就可以直接拒绝,不再需要去数据库里查了。这样就可以防止大部分无效数据查询,屏蔽很多恶意的请求。

布隆过滤器使用一个很长的二进制位数组和一系列哈希函数来保存元素。优点是非常节省空间,并且查询时间也非常快。缺点是有一定的误失败概率以及无法删除元素 ,也无法给元素计数。

  • 位数组(Bit Array):布隆过滤器使用一个长度固定的位数组来存储数据。每个位置只占用一个比特(0或1),初始时所有位都设置为0。位数组的长度和哈希函数的数量决定了过滤器的误报率和容量。
  • 哈希函数集合:布隆过滤器使用多个哈希函数,每个函数都会将输入数据映射到位数组的一个不同位置。哈希函数的选择对过滤器的性能有很大影响,理想的哈希函数应该具有良好的散列性,使得不同的输入尽可能均匀地映射到位数组的不同位置。

在这里插入图片描述

布隆过滤器判断一个元素不在集合中,那么这个元素肯定不在集合中。但是,布隆过滤器判断一个元素在集合中,那么这个元素有可能不在集合中。

2、Guava的布隆过滤器示例

布隆过滤器中,将一个原本不在集合中的元素判断成为在集合中,这就是误判。而误判率是布隆过滤器一个很重要的控制指标。

在算法实现时,误判率是可以通过设定更复杂的哈希函数组合以及做更大的位数组来进行控制的。所以,在布隆过滤器的初始化过程中,通常只需要指定过滤器的容量和误判率,就足够了。

pom.xml引入Guava

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>33.1.0-jre</version></dependency>

使用Guava提供的布隆过滤器实现

public static void main(String[] args) {BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8),10000,0.01);//把 A~Z 放入布隆过滤器for (int i = 64; i <= 90 ; i++) {bloomFilter.put(String.valueOf((char) i));}System.out.println(bloomFilter.mightContain("A")); //trueSystem.out.println(bloomFilter.mightContain("a")); //false}

3、Redis的BloomFilter使用示例

布隆过滤器是用的二进制数组来保存数据,所以,Redis的BitMap数据结构天生就非常适合做一个分布式的布隆过滤器底层存储。只是算法还是需要自己实现。有很多企业实际上也是这么做的。

现在Redis提供了BloomFilter模块后,BloomFilter的使用门槛就更低了。

-- 创建一个key为bf的布隆过滤器,容错率0.01,容量1000。NONSCALING 表示不扩容。如果这个过滤器里的数据满了,就直接报错
BF.RESERVE bf 0.01 1000 NONSCALING
-- 添加元素
BF.ADD bf A
.....
-- 批量添加元素
BF.MADD bf B C D E F G H I-- 如果bf不存在,就创建一个key为bf的过滤器。
BF.INSERT bf CAPACITY 1000 ERROR 0.01 ITEMS hello
-- 查看容量
BF.CARD bf
-- 判断元素是否在过滤器中
## 返回值0表示不在,1表示在
BF.EXISTS bf a
-- 批量判断
BF.MEXISTS bf A a B b
-- 查看布隆过滤器状态
BF.INFO bf
# 依次迭代布隆过滤器中的位数组
BF.SCANDUMP bf 0
## 和SCAN指令使用很像,返回当前访问到的数据和下一次迭代的起点。 当下次迭代起点为0表示数据已经全部迭代完成。
## 主要是可以配合BF.LOADCHUNK 进行备份。

5、Cuckoo Filter

1、CuckooFilter是什么?

布隆过滤器最大的问题是无法删除数据。因此,后续诞生了很多布隆过滤器的改进版本。Cuckoo Filter 布谷鸟过滤器就是其中一种。

相比于布隆过滤器,Cuckoo Filter可以删除数据。而且基于相同的集合和误报率,Cuckoo Filter通常占用空间更少。相对的,算法实现也就更复杂。

不过他同样有误判率。即有可能将一个不在集合中的元素错误的判断成在集合中。布隆过滤器的误报率通过调整位数组的大小和哈希函数来控制,而CuckooFilter的误报率受指纹大小和桶大小控制。

BUSKETSIZE,表示每个桶Busket中存放的元素个数。Cuckoo Filter的数组里存的不是位,而是桶busket,每个桶里可以存放多个数据。同一个桶中存放的数据越多,空间利用率更高,相应的误判率也就越高,性能也更慢。Redis的CuckooFilter实现中,BUSKETSIZE应该是一个在1到255之间的整数,默认的BUSKETSIZE是2。

桶Busket中并不实际保存数据本身,而是保存数据的指纹(可以认为是压缩后的数据,实际上是数据对象的几个低位数据)。指纹越小,HASH冲突造成误判的几率就越小。这个参数的调整比较复杂,Redis的CuckooFilter中不支持调整这个参数。

2、CuckooFilter使用示例

-- 创建默认值
## 容量1000,这个是必填参数。后面几个都是可选参数。这里填的几个就是Redis中的CuckooFilter的默认值
## BUSKETSIZE越大,空间利用率更高,但是误判率也更高,性能更差
## MAXITARATIONS越小,性能越好。如果设置越大,空间利用率就越好。
## EXPANSION 是指空间扩容的比例。
CF.RESERVE cf 1000 BUSKETSIZE 2 MAXITERATIONS 20 EXPANSION 1

其他使用,和布隆过滤器差不多。就是多了个CF.DEL删除元素的指令。

四、Redis Stack补充

1、手动安装Redis扩展模块

Redis Stack的这些扩展模块除了在Redis Cloud上直接使用外,也可以手动集成到自己的Redis服务当中。

登录Redis Cloud,进入下载中心,可以手动下载对应的扩展模块。下载时注意选择对应的Redis版本以及操作系统。

在这里插入图片描述

这是一个最简单的下载途径。另外更建议的方式,是去下载这些扩展模块的源码,然后编译,安装。

下载后获取以.so为后缀的扩展文件。上传到服务器后,在Redis的配置文件中加载这个扩展模块

# Load modules at startup. If the server is not able to load modules
# it will abort. It is possible to use multiple loadmodule directives.
#
loadmodule /root/myredis/redisbloom.so

然后重启Redis服务,就可以使用客户端,登录Redis后查看扩展模块的加载情况。

127.0.0.1:6379> MODULE LIST1.1.  "name"2.  "bf"3.  "ver"4.  (integer) 206125.  "path"6.  "/root/myredis/redisbloom.so"7.  "args"8.  (empty array)

注意:如果模块加载错误,那么Redis服务启动会失败的。这时要去查看日志逐步排查问题。

例如,如果redisbloom.so文件在Linux服务器上,没有添加可执行的x 权限,那么Redis就会启动失败

27425:M 18 Jun 2024 14:07:29.670 # Module /root/myredis/redisbloom.so failed to load: It does not have execute permissions.
27425:M 18 Jun 2024 14:07:29.670 # Can't load module from /root/myredis/redisbloom.so: server aborting

2、Java客户端调用扩展模块

这些扩展模块目前阶段都还是比较新的功能,需要手动进行扩展。所以目前Java的一些客户端工具都还没有集成这些功能。大部分情况下,只能通过lua脚本手动调用这些扩展功能。但是由于在客户端无法确定服务端是否安装了对应的扩展模块,所以,在写lua脚本调用时,一定要注意处理好各种各样的异常情况。

例如,以布隆过滤器为例

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisStackTest {@ResourceRedisTemplate<String,Object> redisTemplate;List<String> keys = List.of("a-bf");@Testpublic void createBloomFilter(){if(!redisTemplate.hasKey("a-bf")){try{String createFilterScriptText= """return redis.call('BF.RESERVE', KEYS[1], '0.01','1000','NONSCALING')""";DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(createFilterScriptText, String.class);String execute = redisTemplate.execute(redisScript,keys);System.out.println("CREATE BF:"+execute);}catch (Exception e){//               e.printStackTrace();System.out.println("COMMAND NOT SUPPORT");}}else{System.out.println("BF KEY is already exists");}}@Testpublic void addData(){if(!redisTemplate.hasKey("a-bf")){System.out.println("BF KEY is not exists");}else{try{String[] args = new String[]{"A","B","C","D","E","F","G"};String addDataScriptText= """for i,arg in ipairs(ARGV) dolocal addRes = redis.call('BF.ADD',KEYS[1],arg)endreturn 'OK'""";DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(addDataScriptText, String.class);System.out.println("ADDDATA BF:"+redisTemplate.execute(redisScript,  keys, args));}catch (Exception e){
//                e.printStackTrace();System.out.println("COMMAND NOT SUPPORTED");}}}@Testpublic void checkData(){if(!redisTemplate.hasKey("a-bf")){System.out.println("BF KEY is not exists");}else{String[] args = new String[]{"A","B","C","D","E","F","G"};String checkDataScriptText= """local checkRes = redis.call('BF.EXISTS',KEYS[1],ARGV[1])return checkRes""";DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(checkDataScriptText, Long.class);try{Long res = redisTemplate.execute(redisScript, keys, args);if(1L == res){System.out.println("KEY EXISTS");} else if (0L==res) {System.out.println("KEY NOT EXISTS");}else{System.out.println("ERROR");}}catch (Exception e){
//                e.printStackTrace();System.out.println("COMMAND NOT SUPPORTED");}}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW提高开发效率技巧----阻塞时钟

在LabVIEW开发中&#xff0c;阻塞时钟&#xff08;Blocking Timed Loops&#xff09;是一种常见且强大的技术&#xff0c;尤其适用于时间关键的应用。在这些应用中&#xff0c;精确控制循环的执行频率是关键任务。阻塞时钟通过等待循环的执行完成后再进入下一次迭代&#xff0c…

如何设置LTE端到端系统

LTE Setup Guide Baseline Hardware Requirements 基础硬件要求 需要2个RF前端和2个装有基于Linux的操作系统的PC。系统架构如下&#xff1a; srsUE&#xff1a;需要1个RF前端和1个PC。srsENB&#xff1a;需要1个RF前端和1个PC。srsEPC&#xff1a;需要1个PC。 系统硬件要…

python实现RC4加解密算法

RC4算法 一、算法介绍1.1 背景1.2 密钥调度算法(KSA)1.3 伪随机生成算法(PRGA) 二、代码实现三、演示效果 一、算法介绍 1.1 背景 RC4算法是由Ron Rivest在1987年为RSA数据安全公司设计的一种流密码算法&#xff0c;其安全性主要依赖于其密钥流的随机性和不可预测性。该算法因…

碰撞检测 | 图解视线生成Bresenham算法(附ROS C++/Python/Matlab实现)

目录 0 专栏介绍1 Bresenham算法介绍2 图解Bresenham算法3 算法流程4 仿真实现4.1 ROS C实现4.2 Python实现4.3 Matlab实现 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划算法轨迹优化实战&#xff0c;包括&#xff…

架构设计之解析CQRS架构模式!

文章首发到公众号&#xff1a;月伴飞鱼 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://har…

【可视化大屏】Python Flask框架介绍

为了能显示真实数据&#xff0c;使用flask快速搭建了一个web应用&#xff0c;然后连接数据库&#xff0c;读取数据库里的数据来进行大屏可视化显示&#xff08;btw&#xff1a;数据是从车主之家网站上爬虫爬的&#xff09; 家人们&#xff01;记得使用专业版的pycharm&#xf…

保证文件只能在公司打开,走出公司就打不开这一神操作如何实现?一文告诉你详情!

在现代企业中&#xff0c;信息安全已经成为一项至关重要的任务。随着企业数据量的不断增加&#xff0c;如何确保敏感信息不被泄露成为企业面临的重要挑战。 其中&#xff0c;一种常见的需求是确保文件只能在公司内部环境中打开&#xff0c;一旦离开公司就无法访问。 本文将详…

计算机组成原理实验三 数据寄存器组R0..R3, MAR, ST, OUT

实验目的和要求 目的&#xff1a;了解模型机中各种寄存器结构、工作原理及其控制方法。 要求&#xff1a;利用CP226 实验系统上的K16..K23 开关做为DBUS 的数据&#xff0c;其它开关做为控制信号&#xff0c;将数据写入寄存器&#xff0c;数据寄存器组R0..R3&#xff0c;地址…

stm32开发环境的配置

keli5的安装 安装上以后&#xff0c;用管理员身份打开软件 复制里面的CID到破解软件里面 将Target调到ARM&#xff0c;然后生成 将注册码复制进软件那个界面&#xff0c;然后AddLIC就破解成功了 调试工具STLink驱动的安装 如果发现带感叹号代表驱动没有安装&#xff0c;但是设…

JavaEE之多线程进阶-面试问题

一.常见的锁策略 锁策略不是指某一个具体的锁&#xff0c;所有的锁都可以往这些锁策略中套 1.悲观锁与乐观锁 预测所冲突的概率是否高&#xff0c;悲观锁为预测锁冲突的概率较高&#xff0c;乐观锁为预测锁冲突的概率更低。 2.重量级锁和轻量级锁 从加锁的开销角度判断&am…

【Python时序预测系列】基于GRU模型实现多变量时间序列预测(案例+源码)

这是我的第363篇原创文章。 一、引言 单站点多变量单步预测问题----基于GRU实现多变量时间序列预测股票价格。 二、实现过程 2.1 读取数据集 dfpd.read_csv("data.csv", parse_dates["Date"], index_col[0]) print(df.shape) print(df.head()) fea_num …

OJ在线评测系统 微服务 OpenFeign调整后端下 nacos注册中心配置 不给前端调用的代码 全局引入负载均衡器

OpenFeign内部调用二 4.修改各业务服务的调用代码为feignClient 开启nacos注册 把Client变成bean 该服务仅内部调用&#xff0c;不是给前端的 将某个服务标记为“内部调用”的目的主要有以下几个方面&#xff1a; 安全性: 内部API通常不对外部用户公开&#xff0c;这样可以防止…

【目标检测】木制地板缺陷破损数据集338张6类VOC+YOLO格式

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;3383 标注数量(xml文件个数)&#xff1a;3383 标注数量(txt文件个数)&#xff1a;3383 标注…

python爬虫案例——处理验证码登录网站(12)

文章目录 前言1、任务目标2、网页分析3、代码编写4、第三方验证码识别平台(超级鹰)前言 我们在爬取某些网站数据时,可能会遇到必须登陆才能获取网页内容的情况,而大部分网站登录都需要输入验证码才能登录成功,所以接下来我将会通过实际案例来讲解如何实现验证码登录网站 1…

前后端分离开发YApid

开头先声明以下&#xff0c;这篇主要用于概念的介绍…… 在当今的互联网应用开发中&#xff0c;前后端分离逐渐成为主流的开发模式。相比于传统的前后端混合开发&#xff0c;这种新模式在灵活性、可维护性和团队协作等方面具有显著优势。 前后端混合开发 在前后端混合开发模式…

气膜淤泥加工厂:创新土壤修复的绿色方案—轻空间

随着城市化进程的加快&#xff0c;土壤污染问题日益严重&#xff0c;淤泥处理成为环保领域亟待解决的重要课题。气膜淤泥加工厂应运而生&#xff0c;提供了一种高效、环保的解决方案&#xff0c;为土壤修复和环境保护注入了新的活力。 高效处理&#xff0c;保障环境安全 气膜淤…

什么是 HTTP 请求中的 options 请求?

在 Chrome 开发者工具中的 Network 面板看到的 HTTP 方法 OPTIONS&#xff0c;其实是 HTTP 协议的一部分&#xff0c;用于客户端和服务器之间进行“预检”或“协商”。OPTIONS 请求的作用是让客户端能够获取关于服务器支持的 HTTP 方法和其他跨域资源共享 (CORS) 相关的信息&am…

2-112基于matlab的协同干扰功率分配模型

基于matlab的协同干扰功率分配模型&#xff0c;带操作界面的功率分配GUI&#xff0c;可以实现对已有功率的分配优化&#xff0c;可以手动输入参数值。4个干扰山区分二批总干扰功率&#xff0c;每个扇区包括威胁总系数、综合压制概率、目标函数增量等。程序已调通&#xff0c;可…

Linux:进程调度算法和进程地址空间

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一 进程调度算法 1.1 进程队列数据结构 1.2 优先级 ​编辑 1.3 活动队列 ​编辑 1.4 过期队列 1.5 active指针和expired指针 1.6 进程连接 二 进程地址空间 2.1 …

HCIP--以太网交换安全(二)

端口安全 一、端口安全概述 1.1、端口安全概述&#xff1a;端口安全是一种网络设备防护措施&#xff0c;通过将接口学习的MAC地址设为安全地址防止非法用户通信。 1.2、端口安全原理&#xff1a; 类型 定义 特点 安全动态MAC地址 使能端口而未是能Stichy MAC功能是转换的…