【面试题】Redis面试题,redis面试题大全带答案

【面试题】Redis面试题 目录 为什么使用缓存?Redis是什么?Redis都有哪些使用场景?Redis有哪些功能?Redis支持的数据类型有哪些?Redis为什么是单

会话管理:Redis可用于存储和管理与用户会话相关的数据。轻松存储和查询用户登录状态、用户权限、购物车内容等。

分布式缓存:Redis可以用作分布式缓存系统的一部分来存储和管理缓存数据。具有高性能、可扩展性、高可用性,可以有效减轻后端数据库的负载。

实时排行榜:Redis的有序集合特性非常适合实现实时排行榜功能。通过将分数和会员信息存储在有序集合中,轻松执行排名和排行榜计算。

综上所述,Redis适用于很多场景,包括缓存、分布式锁、消息队列、计数器、数据存储、会话管理、分布式缓存、实时排名等。

目录

基于本机内存的缓存

如果调用一个API访问数据库,如果这个过程需要2秒,如果每个请求都需要访问数据库,如果这个SQL的查询结果存储在Redis中,那么当时会给服务器带来很大的负载的要求。从Redis 检索而不是访问数据库效率更高,因为Redis 可以定期(例如每分钟)刷新数据。 如果重新启动计算机,写入内存的数据会失效吗?Redis 还提供持久化功能。

哨兵和复制

Sentinel可以管理多个Redis服务器,并提供监控、提醒和自动故障转移功能。 Redis服务器的这两个特性也保证了Redis的高可用性。

单台服务器的资源总是有上限的,主从复制可以将CPU和IO资源与读写分离,将部分CPU和IO负载转移到从服务器上。资源?主/从模式仅用于数据。备份不能扩展内存。每个服务器只负责部分任务;这些服务器构成整体。这组服务器就像一个集群。

为什么使用缓存?

Redis 支持以下数据类型:

字符串:最基本的数据类型。它可以是字符串类型、整数类型或浮点类型。列表:字符串元素的有序列表,可以在列表的两端插入或删除。集合:唯一字符串元素的无序集合,您可以在其上执行相交、组合和比较等操作。排序集:每个元素都与一个分数相关联,并根据分数进行排序。哈希:键值对的无序哈希。地理定位(Geospatial):一种特殊的数据类型,存储地理位置信息,支持距离计算和位置排序。持久列表(Stream):类似日志的数据结构,支持多个消费者从不同位置读取数据。

除了上面提到的数据类型之外,Redis还提供了一些特殊的操作和数据结构,例如位图、延迟队列等。

Redis是什么?

代码更清晰,处理逻辑更简单。不需要考虑各种加锁问题,没有加锁和释放操作,也不存在潜在死锁带来的性能问题。消耗CPU。多核CPU的好处是不具备的,但是可以通过多开几个Redis实例来提高。

Redis都有哪些使用场景?

在Redis 6.0 之前,它是单线程的。 Redis 6.0及更高版本内部使用了基于epoll的多通道服务,甚至可以部署多个Redis服务器来解决单线程问题。 Redis的主要性能瓶颈是内存。内存只是加个记忆棒而已,但联网却是大事。所以redis6内存只是增加了内存条和网络。是一个很大的问题,所以redis6.0引入了多线程的概念,并且redis6.0引入了核心模块来执行读写网络数据、协议解析等网络IO操作。命令仍然是单线程的。

Redis有哪些功能?

Redis支持主/从、从/从同步。第一次进行主从同步时,主节点使用bgsave命令将后续的修改操作记录在内存缓冲区中,等待所有RDB文件同步到复制节点,复制接受完成后。节点在内存中记录RDB 图像。加载完成后,副本节点通知主节点将复制过程中修改的操作记录同步到副本节点,同步过程完成。

Redis支持的数据类型有哪些?

Redis提供了两种持久化方式:RDB(Redis DataBase)和AOF(Append Only File)。

换句话说,RDB 会生成Redis 中存储的数据在各个时间点的快照,并将其保存到磁盘或其他介质上。

AOF从不同的角度实现了持久化。这意味着下次redis重新启动时,只需从前往后重新执行这些写入指令,您的数据就会恢复正常。

事实上,您甚至可以同时使用RDB 和AOF 方法。这种情况下,当redis重启时,首先使用AOF方式进行数据恢复。这是因为AOF方法的数据恢复更加一致。

如果没有数据持久化需求,可以完全关闭RDB和AOF方式。这样的话,redis就变成了一个纯内存数据库,类似于memcache。

Redis为什么是单线程的?

相比memecache,Redis拥有更多的数据结构,支持更丰富的数据操作。

Redis 支持常用的数据类型:String、Hash、List、Set 和Sorted Set。 memecache 仅支持键和值。 内存使用情况比较。 Redis采用哈希结构进行key-value存储,因此内存占用比memecache高。性能对比:Redis仅使用单核,而memecache使用多核。 Redis支持磁盘持久化,但memecache不支持。

通过swap方法,Redis可以将一些长时间没有使用的值交换到磁盘上。 Redis 支持分布式集群,memecache 不支持。

Redis真的是单线程的吗?

Ladyson、Jedis、Lettuce等,官方推荐Ladyson。

Redis同步机制是什么?

Jedis和Redisson都是Java对Redis操作的封装。 Jedis只是封装了Redis API库,其方法与Redis命令非常相似。 Redisson不仅封装了Redis,还封装了对更多数据结构的支持以及比Jedis更广泛的锁定等特性。然而,Jadis 比Ladyson 更加本土化和灵活。

Redis持久化有几种方式?

在实际项目中,可以采用以下方法来保证缓存和数据库数据的一致性:

读缓存前先查询数据库:读取数据时,先查询缓存。如果缓存中没有数据,则在数据库中运行查询。一旦查询到数据,就会将其存储在缓存中,并有适当的过期时间。这可以确保缓存中的数据与数据库中的数据匹配。

Redis 允许您使用SET 命令实现分布式锁定。以下是具体步骤:

客户端尝试运行以下命令:SET lock_key unique_id NX PX lock_time,其中lock_key是锁的名称,unique_id是唯一标识符,NX选项表示仅在键不存在时设置键的值。 去做。 PX 选项旨在设置密钥过期时间。如果命令执行成功,则返回“OK”,表明客户端成功获取锁。客户端执行完业务逻辑后,通过运行命令DEL lock_key来释放锁。如果命令失败,则返回nil 以指示该锁已被另一个客户端持有。在这种情况下,客户端可以选择等待一段时间并尝试再次获取锁,或者放弃锁。

请注意,释放锁时,客户端只能移除自己持有的锁,而不能意外移除其他客户端的锁。为了实现这一点,可以为每个锁分配一个唯一的标识符。客户端在释放锁时必须提供一个标识符。只有当匹配标识符和锁名称同时匹配时,锁才会成功释放。

使用分布式锁时,必须考虑其他情况,例如锁过期设置、延迟问题和停机恢复。因此,在实际应用中,可以考虑使用Redisson等第三方库来简化分布式锁的实现。

Redis和 memecache 有什么区别?

Redis分布式锁无法解决超时问题。分布式锁有超时时间,当程序执行超过锁超时时间就会出现问题。 Redis 的一些常见问题:

锁未释放。锁B已被锁A释放。数据库事务超时锁已过期,Redis主从复制问题尚未完成。

Redis支持的 java 客户端都有哪些?

减少键值长度

保持值长度较短很重要。对于值较大的业务对象,可以将对象序列化为二进制数组。接下来,您需要简化业务并避免存储不必要的数据。在选择排序工具时,您应该选择更有效的序列化工具来减少字节数组的大小。以JAVA为例,这种情况下内置的序列化方法在速度和压缩方面都不够。 您可以选择更高效的序列化工具,例如protostuff、kryo 或其他共享对象池。

对象共享池是指Redis内部维护的一个整数对象池[0-9999]。创建多个整数类型的redisObject会产生内存开销,每个redisObject的内部结构至少占用16个字节,比整数本身的空间消耗还要多。因此,Redis内存维护了一个整数对象池[0-9999]来节省内存。除了整型值对象外,其他类型如list、hash、set、zset内部元素也可以使用整型对象池。因此,在开发中,你应该使用整数对象来节省内存,假设它满足你的需求。 字符串优化

编码优化

控制按键数量

jedis 和 redisson 有哪些区别?

添加多线程线程I/O

Redis 将所有数据存放在内存中。对于小数据包,内存响应时间约为100 纳秒。这也是80%企业单线程处理的极限。 Redis 就足够了。但随着业务场景越来越复杂,一些企业可以轻松处理上亿级的交易,需要更大的QPS。常见的解决方案是对数据进行分区并在分布式架构中使用多个服务器,但这种解决方案有一些非常严重的缺点:

由于Redis服务器太多需要管理,维护成本很高。某些适用于单个Redis 服务器的命令不适用于数据分区。数据分区无法解决热点数据倾斜、重新分配、扩缩容等问题。比较复杂等等。从Redis本身来看,瓶颈主要是网络IO消耗,因为读写系统在Redis运行时需要进行网络读写,因此占用了很大一部分CPU时间,主要有两个方向。

提高网络IO性能的常见实现包括使用DPDK替换内核网络堆栈或使用多线程充分利用多个核心。 这种协议栈优化的方法和Redis关系不大。多线程支持是最有效、最方便的操作方法。综上所述,redis支持多线程主要有两个原因:

目前主线程只能使用一个核心来分担Redis同步IO读写的负载。

如果本地没有实现JVM缓存,它也可以测试你的Redis服务器是否有高并发。因此,redis提出了客户端缓存的解决方案。

客户端1 从服务器检索特定键的值,服务器缓存当前键并将该值返回给客户端1。客户端1检索到值后,将键和值缓存在本地。如果另一个客户端2 将key 的值更改为value2,并且服务器看到该key 缓存在客户端1 上,则会向客户端1 发送无效键值通知,客户端1 将收到该key 值更改为value2。通知后,禁用本地键值ACL细粒度安全控制访问控制列表。

可以根据命令和按键控制访问连接。从redis6开始,还可以通过重命名来调整flushdb、keys*、shutdown等高危命令的权限。提供细粒度的权限控制。

访问权限:您的用户名和密码控制您可以运行的命令以及您可以交互的按键。添加SSL 模块。

通过添加设置,可以在传输过程中使用SSL协议,保证传输过程的安全。

启用SSL 模块会禁用多线程。 添加新的通信协议RESP3。

添加RESP3对等协议以优化服务器和客户端之间的通信。

怎么保证缓存和数据库数据的一致性?

主线程负责接收连接建立请求,获取socket,并将其放入全局等待读处理队列。主线程处理完读事件后,通过RR(round robin)将这些连接分配给这些IO线程。主线程阻塞并等待IO线程读取socket。 主线程完成。 线程以单线程的方式执行请求命令,读取并解析请求的数据,但主线程不会被阻塞。等待IO。线程向套接字写入数据,完成后解除绑定,清除等待队列。

什么是缓存穿透?怎么解决?

女士哨兵

如果您的规模较小,单个主Redis就足以支持您的业务。 Redis集群

Redis官方提供的集群解决方案。对于较大的大小,请选择Redis 集群以通过分片使用更多内存。托恩普罗克斯

Twemprox 是Twitter 开源的Redis 和Memcached 代理服务器,主要用于管理Redis 和Memcached 集群,减少与缓存服务器的直接连接数量。科迪斯

Codis是一个代理中间件。当客户端向Codis发送指令时,Codis会将指令转发给后续的Redis执行,并将结果返回给客户端。一个Codis实例可以连接多个Redis实例,并且可以启动多个Codis实例进行支持。这会增加总体QPS 要求,并且还可能提供灾难恢复。 客户端分片

Redis 集群在推出之前很流行,但如今很少使用。实现在业务代码层,对key进行哈希计算并创建对应的实例。 Redis 实例的操作数据。这种方法对哈希层代码的要求比较高。考虑因素包括节点故障后的替代算法解决方案、数据冲击后的自动脚本恢复、实例监控等。

Redis怎么实现分布式锁?

所有节点相互连接,集群总线端口大小为客户端服务端口+10000(固定值)。集群节点正常,不通过文本协议执行查询。如果集群节点挂起,数据将存储并分布在多个Redis 实例中。一个Redis集群内置了16384个哈希槽,当需要在Redis集群中放置键和值时,Redis首先使用crc16算法计算出键的结果,然后再计算其余部分。将结果转换为16384,使得每个key对应一个编号为0到16383的哈希槽。哈希槽根据节点数量大致均匀地映射到不同的节点。

Redis分布式锁有什么缺陷?

Redis不使用哈希一致性算法,而是使用哈希槽。 Redis共有16384个哈希槽。要计算特定密钥的哈希槽,只需从密钥的CRC16 中获取16384 即可。假设集群中有A、B、C 3个集群节点。如果没有复制模式,每个集群节点包含以下哈希槽:

节点A包含从0到5500的哈希槽,节点B包含从5501到11000的哈希槽,节点C包含从11001到16383的哈希槽。

如果Node B 发生故障,整个集群将因缺少5501 到11000 范围的哈希槽而不可用。

Redis如何做内存优化?

Redis集群架构支持单节点独立模式、一主多从的主从结构、哨兵集群部署模式。

Redis6.0后的新特性?

如果大量的key同时过期,可以同时从数据库中检索数据,这会给数据库带来很大的压力,导致数据库崩溃,导致系统出现502问题。它们可以同时失败,但除非压力足够高,否则不需要访问数据库。因此,为了防止此类问题的发生,最好在数据过期时间上添加一个随机值,让过期时间更加分散。

redis6.0多线程实现机制

Redis阻塞的原因主要有内部和外部两个原因:

内部原因

Redis 主机上的CPU 负载过高可能会导致系统崩溃并导致Redis 出现问题,因为需要太多资源来保存数据。 外因

外部原因主要是服务器引起的,比如切换过程中服务器CPU线程争用过多、内存问题、网络问题等。

熟悉哪些 Redis 集群模式?

通过将数据预加载到缓存中并增加缓存的存储容量来改进缓存。

的数据;调整缓存的存储数据类型;提升缓存的更新频率

Redis 如何解决 key 冲突?

Redis 如果 key 相同,后一个 key 会覆盖前一个 key。如果要解决 key 冲突,最好给 key 取好名区分开,可以按业务名和参数区分开取名,避免重复 key 导致的冲突

了解Redis的事务吗?

Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的 Redis会将一个事务中的所有命令序列化,然后按顺序执行。

redis 不支持回滚“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速。如果在一个事务中的命令出现错误,那么所有的命令都不会执行;如果在一个事务中出现运行错误,那么正确的命令会被执行。
1)MULTI命令用于开启一个事务,它总是返回OK。 MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。2)EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。3)通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。 可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令

redis的过期策略以及内存淘汰机制?

redis采用的是定期删除+惰性删除策略。 为什么不用定时删除策略? 定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略. 定期删除+惰性删除是如何工作的呢?定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。 采用定期删除+惰性删除就没其他问题了么?不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。 在redis.conf中有一行配置

热点数据和冷数据是什么?

热点数据,缓存才有价值 对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存 对于上面两个例子,寿星列表、导航信息都存在一个特点,就是信息修改频率不高,读取通常非常高的场景。对于热点数据,比如我们的某IM产品,生日祝福模块,当天的寿星列表,缓存以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。 数据更新前至少读取两次,缓存才有意义。这个是最基本的策略,如果缓存还没有起作用就失效了,那就没有太大价值了。 那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的压力,比如我们的某助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到Redis缓存,减少数据库压力。

什么是热Key问题,如何解决热key问题?

在Redis中,我们把访问频率高的key,称为热点key如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务
热点Key是怎么产生的呢?主要原因有两个:

用户消费的数据远大于生产的数据,如秒杀、热点新闻等读多写少的场景。请求分片集中,超过单Redi服务器的性能,比如固定名称key,Hash落入同一台服务器,瞬间访问量极大,超过机器瓶颈,产生热点Key问题。
那么在日常开发中,如何识别到热点key呢?

凭经验判断哪些是热Key;客户端统计上报;服务代理层上报
如何解决热key问题?

Redis集群扩容:增加分片副本,均衡读流量;将热key分散到不同的服务器中;使用二级缓存,即JVM本地缓存,减少Redis的读请求。

什么是跳跃表?

跳表是可以实现二分查找的有序链表;每个元素插入时随机生成它的level;最底层包含所有的元素;如果一个元素出现在level(x),那么它肯定出现在x以下的level中;每个索引节点包含两个指针,一个向下,一个向右跳表查询、插入、删除的时间复杂度为O(log n),与平衡二叉树接近

redis的hash冲突怎么办?

redis通过链式哈希解决冲突,也就是同一个桶里面的元素使用链表保存。但是当链表过长就会导致查找性能变差可能。所以redis为了追求块,使用了两个全局哈希表。用于rehash操作,增加现有的哈希桶数量,减少哈希冲突。
开始默认使用【hash表1】保存键值对数据,【hash表2】此刻没有分配空间。当数据越来越多的触发rehash操作,则执行以下操作:

给【hash表2】分配更大的空间将【hash表1】的数据重新映射拷贝到【hash表2】中释放【hash表1】的空间 值得注意的是,将hash表1的数据重新映射到hash表2的过程并不是一次性的,这样会造成redis阻塞,无法提供服务。

而是采用了渐进式rehash,这样每次处理客户端请求的时候,先从【hash表1】第一个索引开始,将这个位置的所有数据拷贝到【hash表2】中,就这样将 rehash 分散到多次请求过程中,避免耗时阻塞

缓存击穿?

缓存击穿是指在使用缓存系统时,一个热门的、经常被访问的数据缓存过期或失效时,大量并发请求同时涌入,直接访问数据库,导致数据库负载剧增,造成系统性能下降甚至崩溃的情况。
解决方案:

加锁或互斥机制:在缓存失效时,只允许一个请求访问数据库,并将结果缓存,其他请求等待并从缓存中获取数据。
热点数据永远不过期:对于热点数据,可以将其缓存时间设置为永不过期,或者设置一个合理的较长过期时间,确保不会频繁去访问数据库。
异步更新缓存:当某个热点数据的缓存过期时,可以使用异步任务来更新缓存,先返回旧的缓存结果给请求,然后在后台异步更新缓存。
限流和降级:对于突发的大量请求,可以采取限流策略,限制并发访问的请求数量,或者通过降级策略返回预设的默认值,避免数据库负载过大。
前置缓存:在缓存层之前添加一个前置缓存(如CDN等),将请求分摊到多个缓存节点,减轻热点数据的单一缓存节点压。

缓存雪崩?

缓存雪崩是指在使用缓存系统时,大量缓存失效或过期,导致原本应该由缓存提供的数据,都需要从数据库中重新加载,从而引发数据库压力剧增、性能下降,甚至系统崩溃的现象。
解决方案:

设置随机过期时间:为了避免大量缓存同时失效,可以为不同的缓存设置稍有差异的过期时间,分散缓存过期的可能性。
二级缓存机制:使用多级缓存,将数据同时存储到多个缓存层,一级缓存失效时可以从二级缓存中获取数据,避免所有缓存同时失效。
并发重建缓存:在缓存失效的时候,通过加锁或者分布式锁的方式,只允许一个请求去加载数据并重新构建缓存,其他请求等待并从缓存中获取数据。
缓存预热:在系统低峰期,提前加载热门的缓存数据,避免在高峰期同时加载大量缓存数据。
容灾备份:设置多个缓存节点,保证缓存的高可用性,一旦某个缓存节点发生故障,可以快速切换到其他节点。
异步更新缓存:对于热点数据,可以使用异步任务来更新缓存,避免大量的请求同时涌入数据库。

Redis多级缓存?

传统的缓存策略一般是请求到达Tomcat服务后,先查询Redis,如果未命中则查询数据库,存在下面的问题:

请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈。Redis缓存失效时,会对数据库产生冲击,比如,春季期间的12306系统,那可是亿级流量,如果只是用Redis,还是有点吃力。所以,就需要多级缓存了 多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat的压力提升性能,

首先我们可以先从浏览器客户端进行缓存查询,如果没有则去nginx查询nginx的本地缓存,如果没有则通过Lua脚本编程去查询Redis,如果redis也未命中时则请求到达Tomcat服务器查询进程缓存,如果没有则最后查询数据库,此时大多数的压力都给到了nginx我们需要在nginx内部编程,所以此时我们可以将nginx部署成集群,准备一个单独的nginx做反向代理,代理到多个做缓存的nginx上
总结来说

浏览器访问静态资源时候,优先读取浏览器本地缓存;访问非静态资源(ajax查询数据)时候,访问服务端;请求到达Nginx后,优先读取Nginx本地缓存;如果Nginx本地缓存未命中,则去直接查询Redis(不经过Tomcat服务器);如果Redis查询未命中,则查询Tomcat;请求进入Tomcat后,优先查询JVM进程缓存;如果JVM进程缓存未命中,则查询数据库

#以上关于【面试题】Redis面试题的相关内容来源网络仅供参考,相关信息请以官方公告为准!

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92409.html

Like (0)
CSDN的头像CSDN
Previous 2024年6月27日
Next 2024年6月27日

相关推荐

  • 现在用的编程是什么

    现在流行的编程语言有多种,包括Python、JavaScript、Java、C#和Go等,每种语言都有其独特的应用场景和优势。Python 是当今广泛使用的高级编程语言。Pytho…

    网站运维 2024年5月12日
    0
  • 如何手动关闭445网口

    目前国内的网络运营商已关闭445端口,但高校网络为达到学术需求,通常使用教育网接入,可能未对445端口进行防护。此外开启防火墙功能,也会阻止电脑接收445端口的

    2024年9月25日
    0
  • 新型蜜罐有哪些?未来方向如何?

    新型蜜罐有哪些?未来方向如何?前言:技术发展为时代带来变革,同时技术创新性对蜜罐产生推动力。
    一、新型蜜罐的诞生
    技术发展为时代带来变革,同时技术创新性对蜜罐产生推动力,通过借鉴不

    网站运维 2024年7月6日
    0
  • 用过才知道,什么样的边界防御最靠谱

    用过才知道,什么样的边界防御最靠谱 自有防火墙、IPS等防御类设备以来,人们在意识上早早的认识到防御是需要自动化的,但在行动上却远远做不到。 做不到的原因是,企业对业务连续性要求非常高&#xff0c

    网站运维 2024年7月5日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注