Redis核心技术与实战【学习笔记】 - 11.响应延迟的波动问题及解决方案

在 Redis 的实际应用中,有一个非常严重的问题,就是 Redis 突然变慢了。举个例子,在秒杀场景下,一旦 Redis 变慢了,大量的用户下单请求就会被拖慢,也就是说,用户提交了下单申请,确没有得到响应,这会给用户带来非常糟糕的体验,甚至可能会导致用户流失。

而且,在实际的生产环境中,Redis 往往只是业务系统中的一个环节,(例如作为缓存或是数据库)。一旦 Redis 上的请求延迟增加,就可能引起业务系统中的一串儿“连锁反应”。

举个小例子: 应用服务器(App Server)要完成一个事务操作,包括在 Mysql 上执行一个写事务,在 Redis 上插入一个标记位,并通过一个第三方服务给用户发送一条完成的消息。 这三个操作需保证原子性,所以如果此时 Redis 的延迟增加,就会拖累 App Server 端整个事务的执行了。
在这里插入图片描述

这个时候,切忌“急病乱投医”。如果没有一套行之有效的应对方案,大多数时候我们只能各种尝试,做无用功。在前面,我们已经学校了会导致 Redis 变慢的潜在阻塞点以及相应的解决方案,即线程异步机制和 CPU 核绑定。除此之外,还有一些因素会导致 Redis 变慢。

1.Redis 真的变慢了吗?

如何判断 Redis 是不是真的变慢了,一个最直接的方法就是查看 Redis 的响应延迟, 这种方法是看 Redis 延迟的绝对值。

大部分的时候,Redis 延迟很低,单在某些时刻,有些 Redis 实例会出现很高的响应延迟,甚至能达到几秒到十几秒,,不过持续时间不长,这也叫延迟 “毛刺”。当你返现 Redis 命令的执行时间突然就增长到了几秒,基本就可以认定是 Redis 变慢了。

但是在不同的软硬件环境下, Redis 本身的绝对性能并不相同。比如,在有的环境中,当延迟为 1ms 时,就判定 Redis 变慢了,但是当你的硬件配置高,那么,在你的运行环境,可能延迟 0.2ms 的时候,你就可以认定 Redis 变慢了。

第二种判断 Redis 是否变慢的方法:基于当前环境下的 Redis 基线性能做判断

所谓基线性能,就是一个系统在低压力、无干扰下的基本性能,这个性能只由当前的软硬件配置决定。

怎么确定基线性能呢?
实际上,从 2.8.7 版本开始,redis-cli 命令提供了 -intrinsic-latency 选项,可以用来监测和统计测试期间内的最大延迟,这个延迟可以作为 Redis 的基线性能。其中,测试时长可以用 --intrinsic-latency 选项的参数来指定。

举个例子,比如说,我们运行下面的命令,该命令会打印 120 秒内监测到的最大延迟。可以看到,这里的最大延迟是 327 微妙,也就是基线性能为 327 微妙。一般情况下,运行 120 就足够监测到最大延迟了,所以,我们可以把参数设置为 120。

redis-cli --intrinsic-latency 120
Max latency so far: 1 microseconds.
Max latency so far: 32 microseconds.
Max latency so far: 105 microseconds.
Max latency so far: 108 microseconds.
Max latency so far: 115 microseconds.
Max latency so far: 250 microseconds.
Max latency so far: 258 microseconds.
Max latency so far: 302 microseconds.
Max latency so far: 327 microseconds.3560345553 total runs (avg latency: 0.0337 microseconds / 33.70 nanoseconds per run).
Worst run took 9702x longer than the average latency.

需要注意的是,基线性能和当前操作系统、硬件配置相关。因此,我们可以把基线性能和 Redis 运行时的延迟结合起来,再进一步判断 Redis 性能是否变慢了。

一般来说,你要把运行时延迟和基线性能进行对比,如果你观察到 Redis 运行时延迟是其基线性能的 2 倍及以上,就可以认定 Redis 变慢了。

判断基线性能这一点,对于在虚拟化环境下运行的 Redis 来说,非常重要。这是因为,在虚拟化环境(如虚拟机或容器)中,由于增加了虚拟化软件层,与物理机相比,虚拟机或容器本身就会引起一定的性能开销,所以基线性能可能会高一些。下面的测试结果,显示的就是某一个虚拟机上运行 Redis 时测的基线性能。

redis-cli --intrinsic-latency 120
Max latency so far: 692 microseconds. 
Max latency so far: 915 microseconds. 
Max latency so far: 2193 microseconds. 
Max latency so far: 9343 microseconds. 
Max latency so far: 9871 microseconds.

可以看到,由于虚拟化软件本身的开销,此时的基线性能已经达到 9.871ms。如果该 Redis 实例的运行延迟为 10 ms,这并不能算作性能变慢,因此此时,运行时延迟只比基线性能增加了 1.3% 。如果,你不了解基线性能,一看到较高的运行时延迟,就有可能误判 Redis 变慢了。

不过,我们通常是通过客户端和网络访问 Redis 服务,为了避免网络对基线性能的影响,刚刚的命令是在服务器端直接运行的,也就是说,我们只考虑服务器端软硬件环境的影响

如果想要了解网络对 Redis 性能的影响,一个简单的方法是用 iPerf 这样的工具,测量从 Redis 客户端到服务端的网络延迟。如果这个延迟有急事号码甚至是几百毫秒,就说明 Redis 运行的网络环境中很可能有大流量的其他应用承诺需在运行,导致网络拥塞了。这个时候,你需要协调网络运行,调整网络的流量分配了。

2.如何应对 Redis 变慢?

经历上一步,你已经能确定 Redis 是否变慢了。一旦发现变慢了,接下来,就要开始查找原因并解决这个问题了。你要基于自己对 Redis 本身的工作原理的理解,并且结合和它交互的操作系统、存储及网络等外部系统关键机制,在借助一些辅助工具来定位原因,并制定行之有效的解决方案。

下图是第一节绘制的 Redis 架构图。你可以重点关注下图上新增的红色模块,也就是 Redis 自身的操作特性、文件系统和操作系统,它们是影响 Redis 性能的三大要素。

在这里插入图片描述

接下来,将从这三大要素入手,结合实际的应用场景,依次介绍从不同要素触发排查和解决问题的实践经验。

2.1 Redis 自身操作特性的影响

首先我们来学习下 Redis 提供的键值对命令操作对延迟性能的影响。重点介绍两类关键操作:慢查询命令和过期 key 操作。

慢查询命令

慢查询命令,是指在 Redis 中执行速度慢的命令,这会导致 Redis 延迟增加。

Redis 提供的命令操作很多,并不是所有命令都慢,这个操作的复杂度有关。所以,要知道 Redis 的不同命令的复杂度。

比如说,Value类型为 String 时,GET/SET 操作主要就是操作 Redis 的哈希表索引,这个操作的复杂度是固定的,为 O(1)。但是当 Value 类型为 Set 时,SORT、SUNION/SMEMBERS 操作的复杂度分别为 O(N+M*log(M))O(N)。其中,N 为 Set 中元素的个数,M 为 SORT 操作返回元素的个数,这个复杂度就增加了很多。Redis 官网中对每个命令的复杂度都有介绍,你可以直接查询。

如何排查这个问题呢? 下面给你排查建议和解决方法,这也是本章第一个方法。

当你发现 Redis 性能变慢时,可以通过 Redis 日志,或者是 latency monitor 工具,查询变慢的请求,根据请求对应的具体命令以及官方文档,确认下是否采用了复杂度高的慢查询命令。

如果的确有大量的慢查询,有两种处理方式:

  1. 用其他高效命令代替:比如说,如果你需要返回一个 Set 中的所有成员时,不要使用 SMEMBERS 命令,而是要使用 SSCAN 多次迭代返回,避免一次返回大量数据,造成线程阻塞。
  2. 当你需要执行排序、交集、并集操作时,可以在客户端完成,而不要用 SORT、SUNION、SINTER 这些命令,以免拖慢 Redis 实例

当然,如果业务逻辑就是要求使用慢查询命令,你得考虑采用性能更好的 CPU,更快的完成查询命令,避免慢查询的影响。

还有一个比较容易忽略的慢查询命令,就是 KEYS。它用于返回和输入模式匹配的所有 key,例如,以下命令返回所有包含 “name
” 字符串的 keys。

KEYS *names*

因为 KEYS 命令会遍历存储的键值对,所以操作延迟高。如果你不了解它的实现而使用了它,就会导致 Redis 性能变慢。所以,KEYS 命令一般不建议用于生产环境中

过期 key 操作

接下来,看下 过期 key 的自动删除机制。 它是 Redis 用来回收内存空间的常用机制,应用广泛,本身就会引起阻塞,导致性能变慢,所以你必须要知道该机制对性能的影响。

Redis 键值对的 key 可以设置过期时间。默认情况下,Redis 每 100 毫秒会删除一些过期 key,具体算法如下:

  1. 采样 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 个数的 key,并将其中过期的 key 全部删除。
  2. 如果超过 25% 的 key 过期了,则重复删除的过程,直到过期 key 比例降至 25% 以下。

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 是 Redis 的一个参数,模式是 20,那么,一秒内基本有 200 个过期 key 会被删除。这一策略对清楚过期 key 释放内存空间很有帮助。如果每秒删除 200 个过期key,并不会对 Redis 造成太多影响。

但是,如果触发了上面这个算法的第二条,Redis 会一直删除以释放内存空间。注意,删除操作是阻塞的Redis 4.0 后可以采用异步线程机制来减少阻塞影响)。所以,一旦该条件触发,Redis 的线程就会被一直执行删除,这样一来,就没有办法正常服务其他的键值操作了,Redis 会变慢。

那么,第二条是如何触发的呢? 其中一个重要来源,就是频繁使用带有相同时间参数的 EXPIREAT 命令设置过期 KEY,这会导致在同一秒内有大量的 key 同时过期。

  • 排查方法:检查业务代码在使用 EXPIREAT 设置 key 过期时间时,是否使用了相同的 unix 时间戳,有没有使用 EXPIRE 命令给批量 key 设置相同的过期秒数。

  • 解决办法:首先要根据实际业务的使用需求,决定 EXPIREAT 和 EXPIRE 的过期时间参数。其实,如果一批 KEY 的确是同时过期,你可以在 EXPIREAT 和 EXPIRE 的过期时间参数上,加上一个一定大小范围的随机数,这样,既保证了 key 在一个邻近的范围内被删除,又避免了同时过期造成的压力。

但是,如果在排查时,发现 Redis 没有执行大量的慢查询命令,也没有同时删除大量过期 key,那就说明,你要关注影响性能的其他机制了,也就是文件系统和操作系统。

Redis 会持久化报错数据到磁盘,这个过程要依赖于文件系统来完成,所以,文件系统将数据写回磁盘的机制,会直接影响到 Redis 持久化的效率。而且,在持久化过程中,Redis 还在接收其他的请求,持久化效率的高低会影响到 Redis 处理请求的性能。

另一方面,Redis 是内存数据库,内存操作非常频繁,所以,操作系统的内存机制会直接影响到 Redis 的处理效率。比如说,Redis 内存不够了,操作系统会启动 swap 机制,这就会直接拖慢 Redis。

2.2 文件系统的影响

为了保证数据可靠性,Redis 会采用 AOF 日志或 RDB 快照。其中,AOF 日志提供了三种写回策略: no、everysec、always。这三种策略依赖文件系统的两个系统调用完成:write 和 fsync。

  • write 只要把日志写到内核缓冲区,就可以返回了,并不需要等待日志实时写回到磁盘。
  • fsync 需要把日志记录写回到磁盘后才能返回,时间较长。

在这里插入图片描述
当写回策略配置为 everysec、always 时,Redis 需要调用 fsync 把日志写回磁盘。但是,这两种写回策略的具体执行情况是不一样的。

在使用 everysec 时,Redis 会允许丢失 1 秒的操作记录,所以 Redis 主线程并不需要确保每个操作记录日志都写回磁盘。而且,fsync 执行时间很长,如果在主线程中执行 fsync 就容易阻塞主线程。所以,当写回策略为 everysec 时,Redis 会使用后台子线程异步完成 fsync 的操作。

而对于 always 来说,Redis 需要确保每个操作记录都写回磁盘,如果用后台子线程异步完成,主线程是无法及时地知道每个操作是否完成了,这就不符合 always 策略的要求了。所以,always 策略是在主线程中完成的。

另外,使用 AOF 日志时,为了避免日志不断增大,Redis 会执行 AOF 重写,生成体量缩小的新 AOF 日志文件。 AOF 重写本身需要的时间很长,也容易阻塞主线,所以 Redis 使用子进程来进行 AOF 重写。

但是,这里有一个潜在的风险带你:AOF 重写会对磁盘进行大量 IO 操作,同时,fsync 又需要等到数据写道磁盘后才能返回,所以,当 AOF 重写的压力比较大时,就会导致 fsync 被阻塞。虽然 fsync 是由后台子线程负责执行的,但是,主线程会监控 fsync 的执行进度。

当主线程使用后台子线程执行了一次 fsync,需要再次把新接收的操作记录写回磁盘时,如果主线程发现上一次的 fsync 没有执行完,那么它就会阻塞。所以,如果后台子线程执行 fsync 频繁阻塞的话(比如 AOF 重写占用了大量的磁盘 IO 带宽),主线程也会阻塞,导致 Redis 性能变慢。

画一张图来展示下磁盘压力小和压力大的情况下,fsync 后台子线程和主线程收到的影响。
在这里插入图片描述
好了,说到这里,你已经了解了,由于 fsync 后台子线程和 AOF 重写子进程的存在,主 IO 线程一般不会被阻塞。但是,如果在重写日志时,AOF 重写子进程的写入量比较大,fsync 线程也会被阻塞,进而进而阻塞主线程,导致延迟增加。

首先,你可以检查下 Redis 配置文件中的 appendsync 配置项,该配置项的取值表明了 Redis 实例使用的是哪种 AOF 写回策略,如下所示:
在这里插入图片描述
如果是 everysec 或 always 配置,请先确认下业务方对数据可靠性的要求,明确是否需要每一秒或每一个操作都记日志。有的业务方不了解 AOF 的机制,和可能直接使用数据可靠性登记最高的 always 配置了。其实在有些场景中(例如,Redis 用于缓存),数据丢了还可以从后端数据库中获取,并不需要很高的数据可靠性。

如果业务对延迟非常敏感,单允许一定量的数据丢失,那么可以把配置项 no-appendfsync-on-rewrite 设置为 yes,如下:

no-appendfsync-on-rewrite yes

这个配置项设置为 yes 时,表示在 AOF 重写时,不进行 fsync操作。也就是说,Redis 把实例命令写到内存后,不调用后台线程进行 fsync 操作,就可以直接返回。当日,如果此时宕机,就会导致数据丢失。反之,如果这个配置项为 no(也是默认配置),在 AOF 重写时,Redis 实例仍然会调用后台线程进行 fsync 操作,这就会给实例带来阻塞。

如果的确需要高性能,同时也需要高可靠,建议你考虑采用高速的固态硬盘作为 AOF 日志的写入设备

高速固态盘的带宽和并发度比传统机械硬盘要高出 10 倍以上。在 AOF 重写和 fsync 后台线程同时执行时,固态硬盘可以提供较为充足的磁盘 IO 资源,让 AOF 重写和 fsync 后台线程的磁盘 IO 资源竞减少,从而降低对 Redis 性能的营销。

2.3 操作系统的影响

swap

如果 Redis 的 AOF 日志策略为 no,或者没有采用 AOF 模式,还有什么问题会导致性能变慢吗?
操作系统的内存 swap

内存 swap 是操作系统里将内存和磁盘间来回换入和换出的机制,涉及到磁盘的读写,所以,一旦触发 swap,无论是被换入数据的进程,还是被换出数据的进程,其性能都会受到慢速磁盘读写的影响。

Redis 是内存数据库,内存使用量大,如果没有控制内存的使用量,或者和其他内存需求大的应用一起运行了,就可能受到 swap 的影响,导致性能变慢。

正常情况下,Redis 的操作都是直接通过访问内存完成,一旦 swap 触发了,Redis 的请求操作需要等待磁盘数据读写完成才行。而且,和刚才说的 AOF 日志文件读写时使用 fsync 线程不同,swap 触发后影响的是 Redis 的主 IO 线程,这会极大的增加 Redis 的响应时间。

通常,触发 swap 的原因主要是物理机器内存不足,对于 Redis 而言,有两种场景情况:

  • Redis 自身使用了大量的内存,导致物理机的可以内存不足。
  • 和 Redis 实例在同一台机器上运行其他进程,在进行大量的文件读写操作。文件读写本身会占用系统内存,这会导致分配给 Redis 的内存变少,进而触发 swap。

针对这个问题,需要增加机器的内存或者使用 Redis 集群

操作系统本身会在后台记录每个进程的 swap 使用情况,即有多少数据量发生了 swap。

可以先通过如下命令查看 Redis 的进程号,这里是 93

$ ./redis-cli info | grep process_id 
process_id: 93

然后,进入 Redis 所在机器的 /proc 目录下该进程目录中:

$ cd /proc/93

最后,运行下面的命令,查看该 Redis 进程的使用情况。在这儿,我只截取了部分结果:

$cat smaps | egrep '^(Swap|Size)'
Size: 584 kB 
Swap: 0 kB 
Size: 4 kB 
Swap: 4 kB 
Size: 4 kB 
Swap: 0 kB 
Size: 462044 kB 
Swap: 462008 kB 
Size: 21392 kB 
Swap: 0 kB

每一行 Size 表示的是 Redis 实例所用的一块内存大小,而 Size 下方的 Swap 和它相对应,表示这块 Size 大小的内存区域有多少已经被换出到磁盘上了。如果这两个值相等,就表示这块内存区域已经完成被换出到磁盘了。

作为内存数据库,Redis 本身就会使用很多大小不一的内存块,所以,你可以看到有很多Size 行,有的很小只有 4KB,有的很大有 462044 kB 。不同内存块被换出到磁盘上的大小也不一样,例如上面结果中的第一个 4KB 内存块,它下发的 Swap 也是 4KB,这表明这个内存块已经被换出了;另外,462044 kB 这个内存块也被换出了 462008 kB,差不多有 462 MB。

这里有个重要的地方需要说明下,当出现 百 MB,甚至 GB 级别的 swap 大小时,说明此时的 Redis 实例的内存压力很大,很有可能会变慢。所以 swap 的大小是排查 Redis 性能变慢是否由 swap 引起的重要指标。

一旦发生内存 swap,最直接的解决办法就是增加机器内存。如果该实例在一个 Redis 切片集群中,可以增加 Redis 集群实例的个数,来分摊每个实例服务的数据量,进而减少每个实例所需的内存量。

如果 Redis 实例和其他操作大量文件的程序(例如数据分析程序)共享机器,你可以将 Redis 实例迁移到单独的机器上运行,以满足它的内存需求。如果该实例正好是 Redis 主从集群的主库,而从库的内存很大,也可以考虑进行主从切换,把2大内存的从库变成主库。

内存大页

除了内存 swap,还有一个和内存相关的因素,即内存大页机制(Transparent Huge Page,THP),也会影响 Redis 性能。

Linux 内核从 2.6.38 开始支持大页内存,该机制支持 2MB 大小的内存也分配,而常规的内存也分配是按 4 KB 的粒度来执行的。

虽然大页内存可以给 Redis 带来内存分配方面的收益,但是,Redis 为了提供数据可靠性保证,需要将数据做持久化保存。这个写入过程由额外的线程执行,所以,Redis 主线程仍然可以接收客户端写请求。客户端的写请求可能会修改正在进行持久化的数据。在这一过程中,Redis 会采用写时复制机制,即 Redis 不会修改内存中的数据,而是将这些数据拷贝一份,再进行修改

如果采用了内存大页,那么,即使客户端只修改 100B 的数据,Redis 也需要拷贝 2MB的大页。相反,若果是常规内存页机制,只用拷贝 4KB。两者相比,你可以看到,当客户端请求修改或者写入数据较多时,内存大页机制将导致大量的拷贝,这就会影响 Redis 正常的访存操作,最终导致性能变慢。

那怎么办呢? 很简单,关闭内存大页,就行了。

首先,我们要先排查下内存大页。方法是:在 Redis 实例上运行的机器上执行如下命令:

cat /sys/kernel/mm/transparent_hugepage/enabled

如果执行结果是 always,就表明内存大页机制被启动了;如果是 never,就表示,内存大页机制被禁止。

下图就就是 always ,表明内存大页机制被启动
在这里插入图片描述

在实际生成环境中部署时,我建议你不要使用内存大页机制,操作也很简单,只要执行下面的命令就可以了:

echo never /sys/kernel/mm/transparent_hugepage/enabled

再次查看,发现是 never,表名内存大页机制被关闭
在这里插入图片描述

2.4 小结

为了方便你应用,我梳理了一个包含 9 个检查点的 CheckList,希望在你遇到 Redis 性能变慢时,按照这些步骤注意检查,高效地解决问题:

  1. 获取 Redis 在当前环境下的基线性能
  2. **是否用了慢查询命令?**如果是的话,就是要其他命令代替,或者把聚合计算放在客户端执行。
  3. **是否对过期 key 设置了相同的过期时间?**对于批量删除的 key,可以在每个 key 的过期时间上加一个一定范围的随机数,避免同时删除。
  4. **是否存在 bigkey?**对于 bigkey 的删除操作,如果是 Redis 4.0 以上的版本,可以直接利用异步线程机制较少主线程阻塞;如果是 Redis 4.0 以前的版本,可以使用 SCAN 命令在客户端完成。
  5. Redis AOF 配置级别是什么?业务层面是否明确需要这一可靠级别?如果需要高性能,同时也允许数据丢失,可以将配置项 no-appendfsync-no-rewrite 设置为 yes,避免 AOF 重写和 fsync 竞争磁盘 IO 资源,导致 Redis 延迟增加。如果既需要高性能有需要高可靠,最好使用高速固态盘作为 AOF 日志的写入盘。
  6. **Redis 实例的内存使用是否过大?发生 swap 了吗?**如果是的话,就增加机器内存,或者是使用 Redis 集群,分摊单机 Redis 键值对数量和内存压力。同时,避免出现 Redis 和其他内存需求大的应用共享机器的情况。
  7. **在 Redis 实例的运行环境中,是否启动了透明大页机制?**如果是的话,直接关闭内存大页机制就行了。
  8. **是否运行了 Redis 主从集群?**如果是的话,把主库实例的数据量大小控制在 2~4GB,以免主从复制时,从库因加载大的 RDB 文件而阻塞。
  9. 是否使用了多核 CPU 或 NUMA 架构的机器运行 Redis 实例? 使用多核 CPU 时,可以给 Redis 实例绑定物理核;使用 NUMA 架构时,需要注意 Redis 实例和网络中断处理程序运行在同一个 CPU Socket 上。

为了保证 Redis 高性能,我们需要给 Redis 充足的计算、内存和 IO 资源,给它提供一个“安静”的环境。

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

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

相关文章

【JavaEE进阶】 图书管理系统开发日记——肆

文章目录 🍃前言🎍约定前后端交互接⼝🍀服务器代码实现🚩控制层🚩业务层🚩数据层 🌴前端代码的修改⭕总结 🍃前言 今天我们来实现修改图书模块 首先我们先来看一下,需要…

【React】redux状态管理、react-redux状态管理高级封装模块化

【React】react组件传参、redux状态管理 一、redux全局状态管理1、redux概述2、redux的组成1.1 State-状态1.2 Action-事件1.3 Reducer1.4 Store 3、redux入门案例1.1 前期准备1.2 构建store1.2.1 在src下新建store文件夹1.2.2 在store文件夹下新建index.ts文件1.2.3 在index.t…

[AIGC] 21世纪Java与Go的相爱相杀

在21世纪的软件开发领域中,Java和Go这两门编程语言可谓是相爱相杀的存在。它们各自拥有着强大的特点和独特的优势,同时也存在着一些明显的竞争和冲突。让我们来看看这两门语言的故事,以及它们之间的深远意义。 文章目录 Java的魅力Go的魅力相…

C++写算法题时常见问题(稳定更新)

目录 1.如何用 getline 函数读取用户输入的一行 2.如何防止用 scanf 读取字符时读取了 换行和空格 3.map和unordered_map的差别和使用 4.“表达式求值”问题解析 5.运行报RE错误 6.在set或者map里面使用结构体 7.运行时报TLE时,时间复杂度问题 8.double类型的…

Photoshop CS6 下载安装教程,保姆级教程,小白也能轻松搞的,附安装包

前言 Adobe Photoshop CS6强大的照片拍摄和突破性的新功能,用于复杂的图形、选择、逼真的绘画和装饰智能。创建惊人的高动态范围(HDR)图像。用逼真的笔触和混合的颜色绘画。消除噪音,添加种子,并绘制一个国家最先进的摄影设备的草图。凭借原…

神经网络不需要懂原理,只需要应用???(附268篇顶会论文)

神经网络不需要弄明白原理,只要会应用就行,这是真的吗? 具体情况具体分析。如果你是论文要求不高,那么就不需要搞太清楚,如果你的毕业要求高,或者想要更高的提升,尤其是想申博、进大厂&#xf…

【C语言】socket编程接收问题

一、recv()函数接收到的返回值为0表示对端已经关闭 在TCP套接字编程中,通过recv()函数接收到的返回值为0通常表示对端已经关闭了套接字的发送部分。这是因为TCP是一个基于连接的协议,其中有定义明确的连接建立和终止流程;当对端调用close()或…

数据分析:当当网书籍数据可视化分析

当当网书籍数据可视化分析 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏📁评论&…

基于场景文字知识挖掘的细粒度图像识别算法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读:基于场景文字知识挖掘的细粒度图像识别算法1、研究背景2、方法提出方法模块 3、试验4、文章贡献 二、RNN代码学习2.1、什么是RNN2…

Mysql学习记录补充

索引 在无索引情况下,就需要从第一行开始扫描,一直扫描到最后一行,我们称之为 全表扫描,性能很低。 如果我们针对于这张表建立了索引,假设索引结构就是二叉树,那么也就意味着,会对age这个字段…

Linux|Grep 命令的 12 个实用示例

您是否曾经遇到过在文件中查找特定字符串或模式的任务,但不知道从哪里开始查找?那么,grep 命令可以拯救你! grep 是一个功能强大的文件模式搜索器,每个 Linux 发行版都配备了它。如果出于某种原因,它没有安…

【C++入门学习指南】:函数重载提升代码清晰度与灵活性

🎥 屿小夏 : 个人主页 🔥个人专栏 : C入门到进阶 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一、函数重载1.1 函数重载的概念1.2 函数重载的作用1.3 C支持函数重载的原理1.4 扩展 &…

C++ STL库详解:容器适配器stack和queue的结构及功能

一、stack 1.1stack的介绍 1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器&#xf…

图数据库(neo4j)在工业控制中的应用

图模型 事物的模型中,除了它自身的某些特征之外,还包括它与其它事物的关系特征,例如一个学生的属性包括姓名,性别,年龄等属性,同时,他还有许多关系属性,比如他属于哪一个院系&#x…

修改照片尺寸好用的工具,分享4款!

在数字时代,照片已成为我们生活的一部分,而如何调整照片尺寸以满足不同的需求,则显得至关重要。今天,我们就来探讨那些可以修改照片尺寸的工具,让你轻松应对各种尺寸需求。 茄子水印相机 这是一款功能强大、操作简单的…

MacBook有必要装清理软件吗?CleanMyMac X v4.14.6 直装特别版 附安装教程

MacBook是苹果公司的一款高端笔记本电脑,但是,随着使用时间的增长,MacBook也会出现一些问题,比如运行缓慢、卡顿、垃圾文件堆积、磁盘空间不足等。这些问题不仅影响了用户的使用体验,也可能对MacBook的寿命和安全性造成…

已经购买了阿里云服务器ECS,如何在上面部署幻兽帕鲁服务器?(一键安装非常简单)

很多人都知道阿里云可以支持一键购买并部署幻兽帕鲁服务器,不需要你进行任何配置,也不用你登录服务器,通过查看和管理计算巢面板就可以了,直接就可以开玩了。但是如果你已经有了一台阿里云服务器ECS那么该怎么去搭建幻兽帕鲁服务器…

Centos 内存和硬盘占用情况以及top作用

目录 只查看内存使用情况: 内存使用排序取前5个: 硬盘占用情况 定位占用空间最大目录 top查看cpu及内存使用信息 前言-与正文无关 生活远不止眼前的苦劳与奔波,它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&…

c++类继承

一、继承的规则 (1)基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为protected时,那么基类成员在派生类中的访问权限最高也为protected,高于protected会降级为protected,但低…