【中间件篇-Redis缓存数据库08】Redis设计、实现、redisobject对象设计、多线程、缓存淘汰算法

Redis的设计、实现

数据结构和内部编码

type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)hash(哈希)、list(列表)、set(集合)、zset (有序集合),但这些只是Redis对外的数据结构。

实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码。

image.png

每种数据结构都有两种以上的内部编码实现,例如list数据结构包含了linkedlist和ziplist两种内部编码。同时有些内部编码,例如ziplist,可以作为多种外部数据结构的内部实现,可以通过object encoding命令查询内部编码。

Redis这样设计有两个好处:

第一,可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,而对外部用户来说基本感知不到。

第二,多种内部编码实现可以在不同场景下发挥各自的优势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist。

redisobject对象

Redis存储的所有值对象在内部定义为redisobject结构体,内部结构如图所示。

image.png

Redis存储的数据都使用redis0bject来封装,包括string、hash、list、set,zset在内的所有数据类型。理解redis0bject对内存优化非常有帮助,下面针对每个字段做详细说明:

type字段

type字段:表示当前对象使用的数据类型,Redis主要支持5种数据类型:string, hash、 list,set,zset。可以使用type { key}命令查看对象所属类型,type命令返回的是值对象类型,键都是string类型。

encoding字段

encoding 字段 :表示Redis内部编码类型,encoding在 Redis内部使用,代表当前对象内部采用哪种数据结构实现。理解Redis内部编码方式对于优化内存非常重要,同一个对象采用不同的编码实现内存占用存在明显差异。

lru字段

lru字段:记录对象最后次被访问的时间,当配置了maxmemory和maxmemory-policy=volatile-lru或者allkeys-lru时,用于辅助LRU算法删除键数据。可以使用object idletime {key}命令在不更新lru字段情况下查看当前键的空闲时间。

image.png

可以使用scan +object idletime 命令批量查询哪些键长时间未被访问,找出长时间不访问的键进行清理, 可降低内存占用。

refcount字段

refcount字段:记录当前对象被引用的次数,用于通过引用次数回收内存,当refcount=0时,可以安全回收当前对象空间。使用object refcount(key}获取当前对象引用。当对象为整数且范围在[0-9999]时,Redis可以使用共享对象的方式来节省内存。

PS面试题,Redis的对象垃圾回收算法-----引用计数法。

*ptr字段

*ptr字段:与对象的数据内容相关,如果是整数,直接存储数据;否则表示指向数据的指针。

Redis新版本字符串且长度<=44字节的数据,字符串sds和redisobject一起分配,从而只要一次内存操作即可。

PS :高并发写入场景中,在条件允许的情况下,建议字符串长度控制在44字节以内,减少创建redisobject内存分配次数,从而提高性能。

image.png

Redis中的线程和IO模型

image.png

Redis 基于 Reactor 模式开发了自己的网络事件处理器 - 文件事件处理器(file event handler,后文简称为 FEH),而该处理器又是单线程的,所以redis设计为单线程模型。

采用I/O多路复用同时监听多个socket,根据socket当前执行的事件来为socket 选择对应的事件处理器。

当被监听的socket准备好执行accept、read、write、close等操作时,和操作对应的文件事件就会产生,这时FEH就会调用socket之前关联好的事件处理器来处理对应事件。

所以虽然FEH是单线程运行,但通过I/O多路复用监听多个socket,不仅实现高性能的网络通信模型,又能和 Redis 服务器中其它同样单线程运行的模块交互,保证了Redis内部单线程模型的简洁设计。

下面来看文件事件处理器的几个组成部分。

socket

文件事件就是对socket操作的抽象, 每当一个 socket 准备好执行连接accept、read、write、close等操作时, 就会产生一个文件事件。一个服务器通常会连接多个socket,多个socket可能并发产生不同操作,每个操作对应不同文件事件。

I/O多路复用程序

I/O 多路复用程序会负责监听多个socket。

image.png

文件事件分派器

文件事件分派器接收 I/O 多路复用程序传来的socket, 并根据socket产生的事件类型, 调用相应的事件处理器。

文件事件处理器

服务器会为执行不同任务的套接字关联不同的事件处理器, 这些处理器是一个个函数, 它们定义了某个事件发生时, 服务器应该执行的动作。

Redis 为各种文件事件需求编写了多个处理器,若客户端连接Redis,对连接服务器的各个客户端进行应答,就需要将socket映射到连接应答处理器写数据到Redis,接收客户端传来的命令请求,就需要映射到命令请求处理器从Redis读数据,向客户端返回命令的执行结果,就需要映射到命令回复处理器当主服务器和从服务器进行复制操作时,
主从服务器都需要映射到特别为复制功能编写的复制处理器。

Redis6中的多线程

Redis6.0之前的版本真的是单线程吗?

Redis在处理客户端的请求时,包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。但如果严格来讲从Redis4.0之后并不是单线程,除了主线程外,它也有后台线程在处理一些较为缓慢的操作,例如清理脏数据、无用连接的释放、大 key 的删除等等。

Redis6.0之前为什么一直不使用多线程?

官方曾做过类似问题的回复:使用Redis时,几乎不存在CPU成为瓶颈的情况,
Redis主要受限于内存和网络。例如在一个普通的Linux系统上,Redis通过使用pipelining每秒可以处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N))的命令,它几乎不会占用太多CPU。

使用了单线程后,可维护性高。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。Redis通过AE事件模型以及IO多路复用等技术,处理性能非常高,因此没有必要使用多线程。单线程机制使得 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等,“线程不安全” 的命令都可以无锁进行。

Redis6.0为什么要引入多线程呢?

Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,对于小数据包,Redis服务器可以处理80,000到100,000 QPS,这也是Redis处理的极限了,对于80%的公司来说,单线程的Redis已经足够使用了。

但随着越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的QPS。常见的解决方案是在分布式架构中对数据进行分区并采用多个服务器,但该方案有非常大的缺点,例如要管理的Redis服务器太多,维护代价大;某些适用于单个Redis服务器的命令不适用于数据分区;数据分区无法解决热点读/写问题;数据偏斜,重新分配和放大/缩小变得更加复杂等等。

所以总结起来,redis支持多线程主要就是两个原因:

• 可以充分利用服务器 CPU 资源,目前主线程只能利用一个核

• 多线程任务可以分摊 Redis 同步 IO 读写负荷

Redis6.0默认是否开启了多线程?

Redis6.0的多线程默认是禁用的,只使用主线程。如需开启需要修改redis.conf配置文件:io-threads-do-reads yes

image.png

开启多线程后,还需要设置线程数,否则是不生效的。同样修改redis.conf配置文件

关于线程数的设置,官方有一个建议:4核的机器建议设置为2或3个线程,8核的建议设置为6个线程,线程数一定要小于机器核数。还需要注意的是,线程数并不是越大越好,官方认为超过了8个基本就没什么意义了。

Redis6.0采用多线程后,性能的提升效果如何?

Redis 作者 antirez 在 RedisConf 2019分享时曾提到:Redis 6 引入的多线程 IO 特性对性能提升至少是一倍以上。国内也有大牛曾使用unstable版本在阿里云esc进行过测试,GET/SET 命令在4线程 IO时性能相比单线程是几乎是翻倍了。如果开启多线程,至少要4核的机器,且Redis实例已经占用相当大的CPU耗时的时候才建议采用,否则使用多线程没有意义。

缓存淘汰算法

当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换 (swap)。交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用。

maxmemory

在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,Redis 提供了配置参数 maxmemory 来限制内存超出期望大小。

当实际内存超出 maxmemory 时,Redis 提供了几种可选策略(maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。

image.png

image.png

Noeviction

 noeviction 不会继续服务写请求
(DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。

volatile-lru

 volatile-lru 尝试淘汰设置了过期时间的
key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。

volatile-ttl

volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。

volatile-random

volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。

allkeys-lru

allkeys-lru 区别于volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。

allkeys-random

allkeys-random跟上面一样,不过淘汰的策略是随机的 key。

volatile-xxx 策略只会针对带过期时间的key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时不必携带过期时间。如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被 LRU 算法淘汰。

LRU 算法

实现 LRU 算法除了需要key/value 字典外,还需要附加一个链表,链表中的元素按照一定的顺序进行排列。当空间满的时候,会踢掉链表尾部的元素。当字典的某个元素被访问时,它在链表中的位置会被移动到表头。所以链表的元素排列顺序就是元素最近被访问的时间顺序。

位于链表尾部的元素就是不被重用的元素,所以会被踢掉。位于表头的元素就是最近刚刚被人用过的元素,所以暂时不会被踢。

image.png

近似 LRU 算法

Redis 使用的是一种近似 LRU 算法,它跟 LRU 算法还不太一样。之所以不使用 LRU 算法,是因为需要消耗大量的额外的内存,需要对现有的数据结构进行较大的改造。近似

LRU 算法则很简单,在现有数据结构的基础上使用随机采样法来淘汰元素,能达到和 LRU 算法非常近似的效果。Redis 为实现近似 LRU 算法,它给每个 key 增加了一个额外的小字段,这个字段的长度是 24 个 bit,也就是最后一次被访问的时间戳。

当 Redis 执行写操作时,发现内存超出maxmemory,就会执行一次 LRU 淘汰算法。这个算法也很简单,就是随机采样出 5(可以配置maxmemory-samples) 个 key,然后淘汰掉最旧的 key,如果淘汰后内存还是超出 maxmemory,那就继续随机采样淘汰,直到内存低于 maxmemory 为止。

image.png

如何采样就是看maxmemory-policy 的配置,如果是 allkeys 就是从所有的 key 字典中随机,如果是 volatile 就从带过期时间的 key 字典中随机。每次采样多少个 key 看的是 maxmemory_samples 的配置,默认为 5。

采样数量越大,近似 LRU 算法的效果越接近严格LRU 算法。

同时 Redis3.0 在算法中增加了淘汰池,新算法会维护一个候选池(大小为16),池中的数据根据访问时间进行排序,第一次随机选取的key都会放入池中,随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。当放满后,如果有新的key需要放入,则将池中最后访问时间最大(最近被访问)的移除。进一步提升了近似 LRU 算法的效果。

Redis维护了一个24位时钟,可以简单理解为当前系统的时间戳,每隔一定时间会更新这个时钟。每个key对象内部同样维护了一个24位的时钟,当新增key对象的时候会把系统的时钟赋值到这个内部对象时钟。比如我现在要进行LRU,那么首先拿到当前的全局时钟,然后再找到内部时钟与全局时钟距离时间最久的(差最大)进行淘汰,这里值得注意的是全局时钟只有24位,按秒为单位来表示才能存储194天,所以可能会出现key的时钟大于全局时钟的情况,如果这种情况出现那么就两个相加而不是相减来求最久的key。

LFU算法

LFU算法是Redis4.0里面新加的一种淘汰策略。它的全称是Least Frequently Used,它的核心思想是根据key的最近被访问的频率进行淘汰,很少被访问的优先被淘汰,被访问的多的则被留下来。

LFU算法能更好的表示一个key被访问的热度。假如你使用的是LRU算法,一个key很久没有被访问到,只刚刚是偶尔被访问了一次,那么它就被认为是热点数据,不会被淘汰,而有些key将来是很有可能被访问到的则被淘汰了。如果使用LFU算法则不会出现这种情况,因为使用一次并不会使一个key成为热点数据。LFU原理使用计数器来对key进行排序,每次key被访问的时候,计数器增大。计数器越大,可以约等于访问越频繁。具有相同引用计数的数据块则按照时间排序。

LFU一共有两种策略:

volatile-lfu:在设置了过期时间的key中使用LFU算法淘汰key

allkeys-lfu:在所有的key中使用LFU算法淘汰数据

LFU把原来的key对象的内部时钟的24位分成两部分,前16位ldt还代表时钟,后8位logc代表一个计数器。

logc是8个 bit,用来存储访问频次,因为8个 bit能表示的最大整数值为255,存储频次肯定远远不够,所以这8个 bit存储的是频次的对数值,并且这个值还会随时间衰减,如果它的值比较小,那么就很容易被回收。为了确保新创建的对象不被回收,新对象的这8个bit会被初始化为一个大于零的值LFU INIT_VAL(默认是=5)。

ldt是16个bit,用来存储上一次 logc的更新时间。因为只有16个 bit,所精度不可能很高。它取的是分钟时间戳对2的16次方进行取模。

ldt的值和LRU模式的lru字段不一样的地方是,
ldt不是在对象被访问时更新的,而是在Redis 的淘汰逻辑进行时进行更新,淘汰逻辑只会在内存达到 maxmemory 的设置时才会触发,在每一个指令的执行之前都会触发。每次淘汰都是采用随机策略,随机挑选若干个 key,更新这个 key 的“热度”,淘汰掉“热度”最低的key。因为Redis采用的是随机算法,如果
key比较多的话,那么ldt更新得可能会比较慢。不过既然它是分钟级别的精度,也没有必要更新得过于频繁。

ldt更新的同时也会一同衰减logc的值。

为什么 Redis 要缓存系统时间戳

我们平时使用系统时间戳时,常常是不假思索地使用System.currentTimeInMillis或者time.time()来获取系统的毫秒时间戳。Redis不能这样,因为每一次获取系统时间戳都是一次系统调用,系统调用相对来说是比较费时间的,作为单线程的Redis承受不起,所以它需要对时间进行缓存,由一个定时任务,每毫秒更新一次时间缓存,获取时间都是从缓存中直接拿。

过期策略和惰性删除

过期

Redis 所有的数据结构都可以设置过期时间,时间一到,就会自动删除。但是会不会因为同一时间太多的key 过期,以至于忙不过来。同时因为Redis 是单线程的,删除的时间也会占用线程的处理时间,如果删除的太过于繁忙,会不会导致线上读写指令出现卡顿。

过期的 key 集合

redis 会将每个设置了过期时间的
key 放入到一个独立的字典中,以后会定时遍历这个字典来删除到期的 key。除了定时遍历之外,它还会使用惰性策略来删除过期的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除。定时删除是集中处理,惰性删除是零散处理。

定时扫描策略

Redis 默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。

1、从过期字典中随机 20 个 key;

2、删除这 20 个 key 中已经过期的 key;

3、如果过期的 key 比率超过 1/4,那就重复步骤 1;

设想一个大型的 Redis 实例中所有的 key 在同一时间过期了,会出现怎样的结果?

毫无疑问,Redis 会持续扫描过期字典 (循环多次),直到过期字典中过期的
key 变得稀疏,才会停止 (循环次数明显下降)。这就会导致线上读写请求出现明显的卡顿现象。导致这种卡顿的另外一种原因是内存管理器需要频繁回收内存页,这也会产生一定的 CPU 消耗。

所以业务开发人员一定要注意过期时间,如果有大批量的 key 过期,要给过期时间设置一个随机范围,而不能全部在同一时间过期。

从库的过期策略

从库不会进行过期扫描,从库对过期的处理是被动的。主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指令来删除过期的 key。

因为指令同步是异步进行的,所以主库过期的
key 的 del 指令没有及时同步到从库的话,会出现主从数据的不一致,主库没有的数据在从库里还存在,比如上一节的集群环境分布式锁的算法漏洞就是因为这个同步延迟产生的。

惰性删除

所谓惰性策略就是在客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。

定期删除可能会导致很多过期key到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,即当你主动去查过期的key时,如果发现key过期了,就立即进行删除,不返回任何东西.

总结:定期删除是集中处理,惰性删除是零散处理。

lazyfree

使用 DEL 命令删除体积较大的键, 又或者在使用
FLUSHDB 和 FLUSHALL 删除包含大量键的数据库时,造成redis阻塞的情况;另外redis在清理过期数据和淘汰内存超限的数据时,如果碰巧撞到了大体积的键也会造成服务器阻塞。

为了解决以上问题, redis 4.0 引入了lazyfree的机制,它可以将删除键或数据库的操作放在后台线程里执行, 从而尽可能地避免服务器阻塞。

lazyfree的原理不难想象,就是在删除对象时只是进行逻辑删除,然后把对象丢给后台,让后台线程去执行真正的destruct,避免由于对象体积过大而造成阻塞。redis的lazyfree实现即是如此,下面我们由几个命令来介绍下lazyfree的实现。

4.0 版本引入了 unlink 指令,它能对删除操作进行懒处理,丢给后台线程来异步回收内存。

UNLINK的实现中,首先会清除过期时间,然后调用dictUnlink把要删除的对象从数据库字典摘除,再判断下对象的大小(太小就没必要后台删除),如果足够大就丢给后台线程,最后清理下数据库字典的条目信息。

主线程将对象的引用从「大树」中摘除后,会将这个 key 的内存回收操作包装成一个任务,塞进异步任务队列,后台线程会从这个异步队列中取任务。任务队列被主线程和异步线程同时操作,所以必须是一个线程安全的队列。

Redis 提供了 flushdb 和 flushall 指令,用来清空数据库,这也是极其缓慢的操作。Redis 4.0 同样给这两个指令也带来了异步化,在指令后面增加 async 参数就会进入后台删除逻辑。

Redis4.0 为这些删除点也带来了异步删除机制,打开这些点需要额外的配置选项。

image.png

1、slave-lazy-flush
从库接受完 rdb 文件后的 flush 操作

2、lazyfree-lazy-eviction
内存达到 maxmemory 时进行淘汰

3、lazyfree-lazy-expire
key 过期删除

4、lazyfree-lazy-server-del
rename 指令删除 destKey

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

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

相关文章

【Spring Boot】034-Spring Boot 整合 JUnit

【Spring Boot】034-Spring Boot 整合 JUnit 文章目录 【Spring Boot】034-Spring Boot 整合 JUnit一、单元测试1、什么是单元2、什么是单元测试3、为什么要单元测试 二、JUnit1、概述简介特点 2、JUnit4概述基本用法 3、JUnit5概述组成 4、JUnit5 与 JUnit4 的常用注解对比 三…

计算机网络期末复习-Part5

1、CRC计算 看例题&#xff1a;待发送序列为101110&#xff0c;生成多项式为X31&#xff0c;计算CRC校验码 先在待发送序列末尾添加与生成多项式次数相同的零&#xff0c;在上述例子中&#xff0c;生成多项式是X^3 1&#xff0c;所以需要添加3个零&#xff0c;待发送序列变成…

一行JavaScrip可以做什么?

说在前面 JavaScript 提供了许多方便的方法和操作符来简化常见的任务&#xff0c;使得编程变得更加高效和便捷。无论是数学计算、字符串处理还是数据操作&#xff0c;JavaScript 都能帮助我们以简洁的方式实现所需功能。 代码 1、生成指定范围内的随机整数 const randomInt …

tensorboard报错解决:No dashboards are active for the current data set

版本&#xff1a;tensorboard 2.10.0 问题&#xff1a;文件夹下明明有events文件&#xff0c;但用tensorboard命令却无法显示。 例如&#xff1a; 原因&#xff1a;有可能是文件路径太长了&#xff0c;导致系统无法读取文件。在win系统中规定&#xff0c;目录的绝对路径不得超…

WordPress 文档主题模板Red Line -v0.2.2

此主题作为框架&#xff0c;做承载第三方页面之用&#xff0c;例如飞书文档等&#xff0c; 您可以将视频图片等资源放第三方文档上&#xff0c;通过使用此主题做目录用。 此主题使用前后端分离开发&#xff0c;也使用了一些技术尽量不影响正常的SEO&#xff0c;还望注意。 源码…

线性代数本质系列(一)向量,线性组合,线性相关,矩阵

本系列文章将从下面不同角度解析线性代数的本质&#xff0c;本文是本系列第一篇 向量究竟是什么&#xff1f; 向量的线性组合&#xff0c;基与线性相关 矩阵与线性相关 矩阵乘法与线性变换 三维空间中的线性变换 行列式 逆矩阵&#xff0c;列空间&#xff0c;秩与零空间 克莱姆…

XML Web 服务 Eclipse实现中的sun-jaxws.xml文件

说明 在sun-jaxws.xml文件&#xff0c;可以配置endpoint、handler-chain等内容。在这个文件中配置的内容会覆盖在Java代码中使用注解属性配置的的内容。 这个文件根据自己的项目内容修改完成以后&#xff0c;作为web应用的一部分部署到web容器中&#xff08;放到web应用的WEB…

【机器学习】K近邻算法:原理、实例应用(红酒分类预测)

案例简介&#xff1a;有178个红酒样本&#xff0c;每一款红酒含有13项特征参数&#xff0c;如镁、脯氨酸含量&#xff0c;红酒根据这些特征参数被分成3类。要求是任意输入一组红酒的特征参数&#xff0c;模型需预测出该红酒属于哪一类。 1. K近邻算法介绍 1.1 算法原理 原理&a…

JavaScript从入门到精通系列第三十六篇:详解JavaScript中的事件监听和事件响应

文章目录 一&#xff1a;什么叫事件 1&#xff1a;概念 2&#xff1a;处理这个事件 (一)&#xff1a;鼠标单机按钮 (二)&#xff1a;鼠标双机按钮 (三)&#xff1a;鼠标移动 3&#xff1a;写法弊端 4&#xff1a;Dom Event 二&#xff1a;监听事件 1&#xff1a;元素事…

域名反查Api接口——让您轻松查询域名相关信息

在互联网发展的今天&#xff0c;域名作为网站的唯一标识符&#xff0c;已经成为了企业和个人网络营销中不可或缺的一部分。为了方便用户查询所需的域名信息&#xff0c;API接口应运而生。本文将介绍如何使用挖数据平台《域名反查Api接口——让您轻松查询域名相关信息》进行域名…

Java之“数字困境”:资产管理项目中的Bug追踪与启示

目录 1 前言2 问题的发现3 调试的开始4 深入调试5 调试心得与反思6 结语 1 前言 在程序员的日常工作中&#xff0c;我们时常面对各种令人头疼的问题&#xff0c;其中最令人崩溃的瞬间之一&#xff0c;就是当我们花费大量时间追踪一个看似复杂的bug&#xff0c;最终发现问题的根…

windows安装composer并更换国内镜像

第一步、官网下载 下载地址 Composer安装https://getcomposer.org/Composer-Setup.exe第二步、双击安装即可 第三步选择 php安装路径并配置path 第四步、 composer -v查看安装是否成功&#xff0c;出现成功界面 第五步、查看镜像地址并更换&#xff08;composer国内可能较慢…

达梦数据库安装

一、官网参考文档 达梦数据库官网&#xff1a;https://www.dameng.com/ &#xff0c;参考文档如下&#xff1a; 最后的文档地址为&#xff1a;Docker安装 | 达梦技术文档 二、dcoker安装 docker基本按照官网来就行&#xff0c;点击相应的链接下载镜像包。 复制到linux中&#x…

万界星空科技智能管理系统低代码平台

低代码平台正成为企业数字化基础设施的重要一环&#xff0c;越来越多的企业为了可持续的数字化建设&#xff0c;开始启用低代码平台&#xff0c;其选型除了平台易用性、应用搭建能力外&#xff0c;也关注与第三方平台的集成性&#xff0c;及厂商对行业knowhow的积累、品牌口碑及…

LeetCode(9)跳跃游戏【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 55. 跳跃游戏 1.题目 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回…

飞天使-django概念之urls

urls 容易搞混的概念&#xff0c;域名&#xff0c;主机名&#xff0c;路由 网站模块多主机应用 不同模块解析不同的服务器ip地址 网页模块多路径应用 urlpatterns [ path(‘admin/’, admin.site.urls), path(‘’, app01views.index), path(‘movie/’, app01views.movi…

5 新的关键字

动态内存分配 回想C语言中&#xff0c;动态内存是怎么分配的&#xff1f;通过C库里面的malloc free去进行动态内存分配。 C通过new关键字进行动态内存申请&#xff0c;动态内存申请是基于类型进行的。 delete 关键字用于内存释放。 //变量申请 type* pointer new type; dele…

Mistral 7B 比Llama 2更好的开源大模型 (一)

Mistral 7B 简介 Mistral 7B Mistral 7B 是一个 7.3B 参数模型: 在所有基准测试中优于 Llama 2 13B在许多基准测试中优于 Llama 1 34B接近 CodeLlama 7B 的代码性能,同时保持擅长英语任务使用分组查询注意力 (GQA) 加快推理速度使用滑动窗口注意力 (SWA) 以更低的成本处…

[Android]新建项目使用AppCompatActivity后运行闪退

报错 日志&#xff1a; Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. FATAL EXCEPTION: main Process: com.example.gatestdemol, PID: 26071 java.lang.RuntimeException: Unable to start a…

DefaultListableBeanFactory

DefaultListableBeanFactory 是一个完整的、功能成熟的 IoC 容器&#xff0c;如果你的需求很简单&#xff0c;甚至可以直接使用 DefaultListableBeanFactory&#xff0c;如果你的需求比较复杂&#xff0c;那么通过扩展 DefaultListableBeanFactory 的功能也可以达到&#xff0c…