Redis设计与实现之对象处理机制

news2024/9/23 17:23:45

目录

一、前言

二、对象处理机制

1、redisObject 数据结构,以及 Redis 的数据类型

2、 命令的类型检查和多态

3、对象共享

4、引用计数以及对象的销毁

三、对象的处理

1、Redis是如何处理字符串对象的?

2、Redis是如何处理列表对象的?

3、Redis是如何处理哈希对象的?

4、Redis是如何处理集合对象的?

5、Redis是如何处理有序集合对象的?

6、Redis是如何处理bitmap对象的?

7、Redis是如何处理hyperloglog对象的?

8、Redis是如何处理地理位置对象的?

9、Redis是如何处理流对象的?

10、Redis是如何处理模块对象的?

四、小结 


一、前言

既然 Redis 的键值对可以保存不同类型的值,那么很自然就需要对键值的类型进行检查以及多态处理。
为了让基于类型的操作更加方便地执行,Redis 创建了自己的类型系统。

在这一部分,我们将对 Redis 所使用的对象系统进行了解,并分别观察字符串、哈希表、列表、集合和有序集类型的底层实现。

二、对象处理机制

在 Redis 的命令中,用于对键(key)进行处理的命令占了很大一部分,而对于键所保存的值的类型(后简称“键的类型” ),键能执行的命令又各不相同。

比如说,LPUSH 和 LLEN 只能用于列表键,而 SADD 和 SRANDMEMBER 只能用于集合 键,等等。

另外一些命令,比如 DEL 、TTL 和 TYPE ,可以用于任何类型的键,但是,要正确实现这些命令,必须为不同类型的键设置不同的处理方式:比如说,删除一个列表键和删除一个字符串 键的操作过程就不太一样。

以上的描述说明,Redis 必须让每个键都带有类型信息,使得程序可以检查键的类型,并为它 选择合适的处理方式。

另外,在前面介绍各个底层数据结构时有提到,Redis 的每一种数据类型,比如字符串、列表、 有序集,它们都拥有不只一种底层实现(Redis 内部称之为编码,encoding),这说明,每当对 某种数据类型的键进行操作时,程序都必须根据键所采取的编码,进行不同的操作。

比如说,集合类型就可以由字典和整数集合两种不同的数据结构实现,但是,当用户执行 ZADD 命令时,他/她应该不必关心集合使用的是什么编码,只要 Redis 能按照 ZADD 命令的 指示,将新元素添加到集合就可以了。

这说明,操作数据类型的命令除了要对键的类型进行检查之外,还需要根据数据类型的不同编 码进行多态处理。

为了解决以上问题,Redis 构建了自己的类型系统,这个系统的主要功能包括: • redisObject 对象。
• 基于redisObject对象的类型检查。
• 基于redisObject对象的显式多态函数。

• 对redisObject进行分配、共享和销毁的机制。 以下小节将分别介绍类型系统的这几个方面。

Note: 因为 C 并不是面向对象语言,这里将 redisObject 称呼为对象一是为了讲述的方便, 二是希望通过模仿 OOP 的常用术语,让这里的内容更容易被理解,redisObject 实际上是只 是一个结构类型。

1、redisObject 数据结构,以及 Redis 的数据类型

redisObject 是 Redis 类型系统的核心,数据库中的每个键、值,以及 Redis 本身处理的参数,都表示为这种数据类型。 redisObject 的定义位于 redis.h :

/*
* Redis 对象 
*/

typedef struct redisObject { 
    // 类型

    unsigned type:4; // 对齐位

    unsigned notused:2; // 编码方式

    unsigned encoding:4;
    // LRU 时间(相对于 server.lruclock)

    unsigned lru:22; // 引用计数

    int refcount; // 指向对象的值

    void *ptr; 
} robj;

type 、encoding 和 ptr 是最重要的三个属性。
type 记录了对象所保存的值的类型,它的值可能是以下常量的其中一个(定义位于 redis.h):

/*
* 对象类型 
*/

#define REDIS_STRING 0 // 字符串 
#define REDIS_LIST 1 // 列表

#define REDIS_SET 2 // 集合

#define REDIS_ZSET 3  // 有序集
#define REDIS_HASH 4 // 哈希表

encoding 记录了对象所保存的值的编码,它的值可能是以下常量的其中一个(定义位于 redis.h):

/*
* 对象编码 
*/

#define REDIS_ENCODING_RAW 0 // 编码为字符串
#define REDIS_ENCODING_INT 1 // 编码为整数
#define REDIS_ENCODING_HT 2 // 编码为哈希表 
#define REDIS_ENCODING_ZIPMAP 3 // 编码为 zipmap 
#define REDIS_ENCODING_LINKEDLIST 4 // 编码为双端链表 
#define REDIS_ENCODING_ZIPLIST 5 // 编码为压缩列表 
#define REDIS_ENCODING_INTSET 6 // 编码为整数集合
#define REDIS_ENCODING_SKIPLIST 7 // 编码为跳跃表

 

ptr 是一个指针,指向实际保存值的数据结构,这个数据结构由 type 属性和 encoding 属性决 定。

举个例子,如果一个 redisObject 的 type 属性为 REDIS_LIST ,encoding 属性为 REDIS_ENCODING_LINKEDLIST ,那么这个对象就是一个 Redis 列表,它的值保存在一个双 端链表内,而 ptr 指针就指向这个双端链表;

另一方面,如果一个 redisObject 的 type 属性为 REDIS_HASH ,encoding 属性为 REDIS_ENCODING_ZIPMAP ,那么这个对象就是一个 Redis 哈希表,它的值保存在一个 zipmap 里,而 ptr 指针就指向这个 zipmap ;诸如此类。

下图展示了 redisObject 、Redis 所有数据类型、以及 Redis 所有编码方式(底层实现)三者 之间的关系:

这个图展示了 Redis 各种数据类型,以及它们的编码方式。
Note: REDIS_ENCODING_ZIPMAP 没有出现在图中,因为从 Redis 2.6 开始,它不再是任何数据类型的底层结构。

2、 命令的类型检查和多态

有了 redisObject 结构的存在,在执行处理数据类型的命令时,进行类型检查和对编码进行多态操作就简单得多了。 当执行一个处理数据类型的命令时,Redis 执行以下步骤:

  1. 根据给定key,在数据库字典中查找和它像对应的redisObject,如果没找到,就返回 NULL。

  2. 检查redisObject的type属性和执行命令所需的类型是否相符,如果不相符,返回类 型错误。

  3. 根据redisObject的encoding属性所指定的编码,选择合适的操作函数来处理底层的 数据结构。

  4. 返回数据结构的操作结果作为命令的返回值。

作为例子,以下展示了对键 key 执行 LPOP 命令的完整过程:

3、对象共享

有一些对象在 Redis 中非常常见,比如命令的返回值 OK 、ERROR 、WRONGTYPE 等字符外,一些小范围的整数,比如个位、十位、百位的整数都非常常见。

为了利用这种常见情况,Redis 在内部使用了一个 Flyweight 模式 :通过预分配一些常见的值 对象,并在多个数据结构之间共享这些对象,程序避免了重复分配的麻烦,也节约了一些 CPU 时间。

Redis 预分配的值对象有如下这些:

  • 各种命令的返回值,比如执行成功时返回的OK,执行错误时返回的ERROR,类型错误时返回的 WRONGTYPE ,命令入队事务时返回的 QUEUED ,等等。

  • 包 括 0 在 内, 小 于 redis.h/REDIS_SHARED_INTEGERS 的 所 有 整 数(REDIS_SHARED_INTEGERS 的默认值为 10000)

    因为命令的回复值直接返回给客户端,所以它们的值无须进行共享;另一方面,如果某个命令 的输入值是一个小于 REDIS_SHARED_INTEGERS 的整数对象,那么当这个对象要被保存进数据 库时,Redis 就会释放原来的值,并将值的指针指向共享对象。作为例子,下图展示了三个列表,它们都带有指向共享对象数组中某个值对象的指针:

    三个列表的值分别为:

  • • 列表 A :[20130101, 300, 10086] ,

  • • 列表 B :[81, 12345678910, 999] ,

  • • 列表 C :[100, 0, -25, 123] 。

    Note: 共享对象只能被带指针的数据结构使用。 需要提醒的一点是,共享对象只能被字典和双端链表这类能带有指针的数据结构使用。

    像整数集合和压缩列表这些只能保存字符串、整数等字面值的内存数据结构,就不能使用共享 对象。

    4、引用计数以及对象的销毁

    当将 redisObject 用作数据库的键或者值,而不是用来储存参数时,对象的生命期是非常长 的,因为 C 语言本身没有自动释放内存的相关机制,如果只依靠程序员的记忆来对对象进行追 踪和销毁,基本是不太可能的。

    另一方面,正如前面提到的,一个共享对象可能被多个数据结构所引用,这时像是“这个对象被 引用了多少次? ”之类的问题就会出现。

    为了解决以上两个问题,Redis 的对象系统使用了引用计数技术来负责维持和销毁对象,它的 运作机制如下:

    • 每个redisObject结构都带有一个refcount属性,指示这个对象被引用了多少次。

  • • 当新创建一个对象时,它的refcount属性被设置为1。

  • 当对一个对象进行共享时,Redis 将这个对象的 refcount 增一。

  • 当使用完一个对象之后,或者取消对共享对象的引用之后,程序将对象的refcount减 一。

  • 当对象的refcount降至0时,这个redisObject结构,以及它所引用的数据结构的内 存,都会被释放。

三、对象的处理

1、Redis是如何处理字符串对象的?

在Redis中,字符串对象是指存储在键值对中的值,Redis使用简单动态字符串(Simple Dynamic String,SDS)数据结构来表示字符串对象。SDS是一种C语言的字符串抽象,类似于C语言中的字符串,但是它比C字符串更灵活并且可以动态修改大小。

当一个字符串被存储在Redis中时,Redis会根据字符串的长度来自动选择使用普通字符串对象或者SDS对象。如果一个字符串的长度小于等于39字节,那么Redis会使用普通字符串对象来表示。普通字符串对象是一个包含了指向字符数组的指针和字符串长度的结构体。如果一个字符串的长度大于39字节,那么Redis会使用SDS对象来表示。SDS对象是一个结构体,包含了字符串的长度、空余空间、字符数组和其他属性。

SDS字符串对象相较于C字符串具有以下优势:

  1. O(1)复杂度的常数时间获取字符串长度,而C字符串需要遍历整个字符串才能获取长度;
  2. 自动扩展和缩小字符串的空间,避免了缓冲区溢出和内存浪费;
  3. 记录了字符串的使用场景,可以根据场景对字符串进行优化处理;
  4. 支持二进制安全,可以存储任意二进制数据。

Redis的字符串对象在内存中以字节数组的形式存储,这使得Redis可以快速地对字符串进行读写操作。此外,Redis还提供了一系列的命令和操作符来处理字符串对象,如获取字符串长度、追加字符串、截取字符串、替换字符串等。通过这些操作,Redis可以高效地处理和操作字符串数据。

2、Redis是如何处理列表对象的?

Redis处理列表对象是通过使用链表数据结构来实现的。在Redis中,列表对象实际上是一个双向链表,每个节点都包含一个指向前一个节点和后一个节点的指针,以及存储实际数据的值。

当我们执行列表操作(例如插入、删除、更新等)时,Redis会根据需要操作链表来实现。例如,当我们执行LPUSH命令向列表的头部插入一个元素时,Redis会创建一个新的节点,并将其放置在头部的位置。之前的头节点将被指向新节点。

由于Redis使用链表来存储列表对象,所以在操作链表时,插入、删除、更新等操作都是常数时间复杂度(O(1))的。这使得Redis非常适合处理需要频繁插入、删除和更新操作的列表场景。

需要注意的是,虽然Redis的列表对象实际上使用链表实现,但它并不是一个完整的链表数据结构,它只实现了链表的基本操作,如插入、删除、更新等。如果需要更复杂的链表操作,可能需要在客户端或服务器端编写自定义逻辑来实现。

3、Redis是如何处理哈希对象的?

Redis中的哈希对象是指一个键值对集合,其中键是一个字符串,值是由字段和字段值组成的映射。Redis使用哈希对象来表示和存储一些类似于对象的数据结构,例如用户信息、商品信息等。

Redis使用一种称为"ziplist"的压缩列表来存储小型哈希对象。ziplist是一种连续的内存结构,可以高效地存储多个键值对。对于小型哈希对象,Redis将整个哈希对象存储在一个ziplist中。

对于较大的哈希对象,Redis会使用一种称为"hashtable"的哈希表来存储。哈希表是一种散列数据结构,可以更高效地处理较大的键值对集合。Redis使用MurmurHash2算法来计算键的哈希值,并使用开链法处理哈希碰撞。

Redis提供了一系列的命令来操作哈希对象,例如HSET、HGET、HDEL等。通过这些命令,可以向哈希对象添加字段、获取字段的值,以及删除字段等操作。

总结起来,Redis使用ziplist和hashtable两种数据结构来处理哈希对象,具体的选择取决于哈希对象的大小。通过使用压缩列表和哈希表,Redis能够高效地处理不同大小的哈希对象,提供快速的读写操作。

4、Redis是如何处理集合对象的?

在Redis中,集合对象是一种无序的、不重复的数据结构。Redis提供了一系列的命令来处理集合对象。以下是一些常用的集合操作命令:

  1. SADD key member [member ...]:向集合中添加一个或多个成员。
  2. SREM key member [member ...]:从集合中移除一个或多个成员。
  3. SCARD key:获取集合的成员数量。
  4. SMEMBERS key:返回集合中的所有成员。
  5. SISMEMBER key member:判断指定成员是否在集合中。
  6. SINTER key [key ...]:返回多个集合的交集。
  7. SUNION key [key ...]:返回多个集合的并集。
  8. SDIFF key [key ...]:返回多个集合的差集。
  9. SRANDMEMBER key [count]:随机获取集合中的一个或多个成员。
  10. SPOP key [count]:随机移除并返回集合中的一个或多个成员。

Redis的集合对象是基于哈希表实现的,所以集合的添加、删除、查找等操作的时间复杂度都是O(1)。此外,Redis还提供了一些集合操作的命令,如求交集、并集、差集等,这些操作的时间复杂度取决于操作的集合数量。

5、Redis是如何处理有序集合对象的?

在Redis中,有序集合(Sorted Set)是一个集合,其中的每个成员都关联着一个分数,分数用于对成员进行排序。有序集合的成员是唯一的,但分数可以重复。

Redis使用一种叫做跳跃表(Skip List)的数据结构来实现有序集合。跳跃表是一个有序的链表,并且通过一些特殊的指针,使得查找操作可以快速跳到链表的某个位置。

在跳跃表中,每个节点都保存了一个成员以及其对应的分数。通过比较成员的分数,可以进行排序。每个节点还保存了一个向右的指针,指向链表中下一个节点。此外,每个节点还会有一个向下的指针,指向同一层中的下一个节点。这些向下的指针可以在查找时快速跳过一些节点,从而提高查找的效率。

由于跳跃表是有序的,所以在插入、删除或更新有序集合中的成员时,只需要对跳跃表进行相应的操作即可。这些操作的时间复杂度通常是O(log N),其中N是有序集合中的成员数量。

总之,Redis使用跳跃表来实现有序集合,通过成员的分数进行排序,并提供高效的插入、删除和查找操作。

6、Redis是如何处理bitmap对象的?

Redis使用位图对象(bitmap)来表示一系列的二进制数据。每个bit位可以被设置为0或1。Redis提供了一系列的命令来操作位图对象,包括设置、获取、计数、位运算等。

Redis使用字符串来存储位图对象,每个bit位对应字符串中的一个字符。Redis会将多个bit位存储在同一个字符串中,以节省内存空间。Redis使用字节序来存储位图对象,从左到右依次存储每个bit位。每个字节可以存储8个bit位。

Redis提供了以下命令来操作位图对象:

  • SETBIT key offset value:设置指定位的值,offset表示位的偏移量,value为0或1。如果key不存在,会自动创建一个新的位图对象。
  • GETBIT key offset:获取指定位的值,offset表示位的偏移量。
  • BITCOUNT key [start end]:获取指定范围内的位为1的个数,start和end表示范围的起始和结束位的偏移量。
  • BITOP operation destkey key [key ...]:对多个位图对象进行位运算,并将结果保存到destkey。operation可以是AND、OR、XOR和NOT。
  • 其他还有一些位图相关的命令,如BITPOS, BITFIELD等。

通过以上命令,可以方便地对位图对象进行各种操作,如统计位为1的个数、对多个位图对象进行位运算、判断某个位是否为1等。位图对象在实际应用中常用于统计、计数、过滤、去重等场景。

7、Redis是如何处理hyperloglog对象的?

Redis在处理hyperloglog对象时,使用一种名为HyperLogLog算法的基数估计算法。这种算法可以用于估计一个集合中不重复元素的数量。

具体而言,Redis中的hyperloglog对象实际上是一个稀疏的位数组,由底层的二进制字符串表示。这个位数组的长度是固定的,并且通常较短,以节省内存空间。

在向hyperloglog对象添加元素时,Redis会通过一个哈希函数将元素映射到一个位数组的索引位置,并将对应位置的位设置为1。这样,hyperloglog对象就可以通过统计位数组中为1的位的数量来估计集合中的不重复元素数量。

当用户需要获取估计的集合大小时,Redis会对位数组进行一定的处理,计算其中为1的位的数量,并使用HyperLogLog算法进行修正和估计。这个修正过的估计值会返回给用户。

需要注意的是,HyperLogLog算法是一种概率性算法,所以它提供的估计结果不是精确的。但是,它的估计结果通常非常接近实际的集合大小,并且相对于传统的存储方式,它占用的内存空间要大大减少。

8、Redis是如何处理地理位置对象的?

Redis处理地理位置对象的主要方式是使用Geo数据结构。Redis的Geo数据结构使用了有序集合(sorted set),其中地理位置对象被存储为成员(member),而经度和纬度被存储为分数(score)。

通过使用Geo数据结构,Redis提供了一系列的地理位置操作,包括添加地理位置对象、获取地理位置对象的经纬度、计算两个地理位置之间的距离等。

具体地,Redis的Geo数据结构包括以下命令:

  • GEOADD:添加地理位置对象到有序集合中。
  • GEORADIUS和GEORADIUSBYMEMBER:根据给定的经纬度和半径,获取在指定范围内的地理位置对象。
  • GEOPOS:获取地理位置对象的经纬度。
  • GEODIST:计算两个地理位置之间的距离。

通过这些命令,Redis可以高效地处理地理位置对象,并提供丰富的地理位置操作功能。

9、Redis是如何处理流对象的?

Redis是一个键值存储数据库,它将数据存储为键值对。在Redis中,可以将流对象存储为一个字符串类型的值。

当需要处理流对象时,可以使用Redis提供的一些命令和数据结构。以下是几个常用的处理流对象的方式:

  1. 字符串操作:使用Redis提供的字符串操作命令,例如GET和SET命令,可以将流对象存储为字符串,并且可以对字符串进行增删改查的操作。

  2. 列表操作:使用Redis提供的列表数据结构,例如LPUSH和RPUSH命令,可以将流对象存储为列表中的元素,可以通过索引对列表进行读取和修改。

  3. 哈希操作:使用Redis提供的哈希数据结构,例如HSET和HGET命令,可以将流对象存储为哈希表中的字段和值,可以通过字段进行读取和修改。

  4. 集合操作:使用Redis提供的集合数据结构,例如SADD和SMEMBERS命令,可以将流对象存储为集合中的元素,可以对集合进行交集、并集和差集等操作。

除了上述的基本操作,Redis还提供了更高级的功能,如发布/订阅模式、事务、Lua脚本等,可以更灵活地处理流对象的存储和操作。

总的来说,Redis通过将流对象存储为字符串、列表、哈希表或集合等不同的数据结构来处理流对象,并且提供了一系列的命令和数据结构,使得对流对象的操作更加方便和高效。

10、Redis是如何处理模块对象的?

在Redis中,模块对象是通过Module API来处理的。Redis模块允许开发者通过编写C语言代码来创建自定义的模块,为Redis添加新的功能和命令。

模块对象在Redis中被表示为一个结构体,包含一些成员变量和方法。其中,成员变量用于存储模块的状态和数据,而方法用于实现模块的功能和处理请求。

Redis提供了一组函数和宏来注册模块对象并与其进行交互。开发者可以使用RedisModule_CreateCommand函数注册自定义命令,使用RedisModule_Call函数调用命令,使用RedisModule_ReplyWith...系列函数回复客户端请求。

模块对象可以在Redis的运行时加载和卸载。在加载模块时,Redis会调用模块的初始化函数来进行一些必要的初始化工作。在卸载模块时,Redis会调用模块的清理函数来释放资源和回收内存。

通过模块对象,开发者可以实现自定义的数据类型、数据结构和命令,扩展Redis的功能和性能。

四、小结 

  • Redis 使用自己实现的对象机制来实现类型判断、命令多态和基于引用计数的垃圾回收。

  • 一种 Redis 类型的键可以有多种底层实现。

  • Redis 会预分配一些常用的数据对象,并通过共享这些对象来减少内存占用,和避免频繁 地为小对象分配内存。

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

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

相关文章

Arduino中以太网Udp通信

目录 1、测试硬件 2、程序 (0)头文件添加 (1)变量定义 (2)初始化程序 (3)循环执行程序 3、程序下载 (1)开发板控制器和端口号选择 (2&am…

java基础知识④:设计模式

目录 一、设计模式 1️⃣创建型设计模式(常用:单例、工厂、抽象工厂) 2️⃣结构型设计模式(常用:适配器、装饰者、外观、代理) 3️⃣行为型设计模式(常用:观察者、策略、模板方法、命…

windows下redis 设置开机自启动

1,在redis的目录下执行(执行后就作为windows服务了) redis-server --service-install redis.windows.conf 2,安装好后需要手动启动redis redis-server --service-start 3,停止服务 redis-server --service-stop

springMVC 学习总结(四) 拦截器及统一异常处理

一.拦截器 1.拦截器与过滤器的区别 拦截器 Interceptor 和 过滤器 Filter类似,主要用于拦截用户请求并作出一定处理操作, 但两则也有不同之处,如过滤器只在Servlet前后起作用,是Servlet规范定义的,是Servlt容器才支…

邮政快递查询,邮政快递单号查询,根据更新量筛选出需要的单号

批量查询邮政快递单号的物流信息,并根据物流更新量将需要的单号筛选出来。 所需工具: 一个【快递批量查询高手】软件 邮政快递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,第一次使用的伙伴记得先注册&…

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取 1.软硬件准备2.关于STM32的Flash的一些说明3.实验结果 参考博主-STM32系列(HAL库)——内部FLASH读写实验 1.软硬件准备 软件:CubeMX、SSCOM(串口调试助手) 硬件:SMT32F…

SQL进阶理论篇(七):B+树的查询及存储机制

文章目录 简介数据库中的存储结构数据库中的页结构从数据页来看B树的查询过程总结参考文献 简介 我们之前已经了解过数据库的B树索引和Hash索引,这些索引信息以及数据记录都是保存在文件里的,确切的说是存储在页结构中。 本节,从我们将了解…

Agilent安捷伦34972A数据采集仪34908A采集卡

附加功能: 3插槽LXI数据采集单元,带6位数字数字多用表(22位)和8个插件模块可供选择(单独出售) 测量11种不同的输入信号(无外部信号调理),包括热电偶、RTD和热敏电阻的温度;DC/交流伏特或电流;2线或4线电阻;频率和周期…

FindMy技术用于滑雪板

随着冬季运动的日益普及,滑雪板作为滑雪运动的重要器材,也变得越来越受欢迎。在各大雪场和户外运动场所,人们纷纷挥舞着滑雪板,畅享冬季运动的乐趣。 在滑雪过程中,由于雪场的复杂环境和运动的高速性,很容易…

数据结构之排序

目录 ​ 1.常见的排序算法 2.插入排序 直接插入排序 希尔排序 3.交换排序 冒泡排序 快速排序 hoare版本 挖坑法 前后指针法 非递归实现 4.选择排序 直接选择排序 堆排序 5.归并排序 6.排序总结 一起去,更远的远方 1.常见的排序算法 排序:所…

Linux学习笔记-Ubuntu下ssh服务器连接异常Connection reset

文章目录 一、问题问题现象1.1 连接重置无法访问的的问题1.2 查看服务器连接状态1.3 使用调试模式查看的信息 二、临时解决方法三、从根源解决问题3.1 问题分析3.2 服务器的ssh日志3.3 修改ssh配置禁止root登录3.4 配置允许所有ip访问3.5 修改认证方法 角色:百世经纶…

自动化访客互动:提升网站效益与用户体验的关键优势

在激烈的市场竞争环境中,想抢占市场,获得收益并不容易。每一个订单的完成都要经过一定的销售周期,所以企业可以根据销售周期每个阶段的特点进行优化,留住客户。其中,企业可以在与客户在线互动的过程中,让互…

缓存一致性几种解决方案

文章目录 一、理论知识1、概述2、坏的方案2.1 先写 MySQL,再写 Redis2.2 先写 Redis,再写 MySQL2.3 先删除 Redis,再写 MySQL 3、好的方案3.1 先删除 Redis,再写 MySQL,再删除 Redis3.2 先写 MySQL,再删除 …

离散数学知识点-期末复习

目录 一、利用真值表求主析取范式、主合取范式 1.例题 二、推理证明 1.推理规则 2.例题 三、符号化命题 四、有穷集的计数 1.包含互斥原理 2.例题 ​1.文氏图法 2.包含互斥原理法 五、关系的闭包 1.三种闭包 2.Warshall算法 3.例题 六、等价关系 1.定义 2.…

杰卡德的故事

三个男人分别是杰卡德距离 杰卡德相似系数和杰卡德系数 杰卡德相似系数和杰卡德距离是互为相反数的。 杰卡德系数和杰卡德距离是不是一回事 感觉是一回事

Linux--Docker容器(最新)

这里写目录标题 安装Docker安装指令配置加速器 Docker简介名词解释作用run命令解读 操作常见命令命令的别名 数据卷简介数据卷命令使用 本地目录挂载问题发现问题解决二级目录二级目录 安装Docker 安装指令 如下文档 https://b11et3un53m.feishu.cn/wiki/Rfocw7ctXij2RBkShcu…

TrustGeo代码理解(五)sublayers.py

代码链接:https://github.com/ICDM-UESTC/TrustGeo 一、导入模块 import torch import torch.nn as nn import torch.nn.functional as F 这段代码是一个简单的神经网络的定义,用于深度学习任务。 1、import torch:导入 PyTorch 库,提供张量(tensor)等深度学习操作的…

Day62力扣打卡

打卡记录 统计区间中的整数数目(动态开点线段树) 链接 class CountIntervals:__slots__ left, right, l, r, cntdef __init__(self, l1, r10 ** 9):self.left self.right Noneself.l, self.r, self.cnt l, r, 0def add(self, l: int, r: int) ->…

Spring cloud - 断路器 Resilience4J

其实文章的标题应该叫 Resilience4J,而不是Spring Cloud Resilience4J,不过由于正在对Spring cloud的一系列组件进行学习,为了统一,就这样吧。 概念区分 首先区分几个概念 Spring cloud 断路器:Spring Cloud的官网对…

Python的数据类型及举例集合、元组、列表之间的转换规则

Python语言有八种数据类型,有数字(整数、浮点数、复数)、字符串、字典、集合、元组、列表、布尔值、空值,下面我演示八种数据类型及集合、元组、列表三种类型之间的转换规则。 一、数据类型示例 下面我演示了八种数据类型&#…