[Java 后端面试题]2024-7-22

Redis的持久化机制,在真实的线上环境中需要采取什么样的策略

在真实的线上环境中,Redis的持久化机制主要有两种:RDB(Redis DataBase)和AOF(Append Only File)。每种机制都有其优点和适用场景,实际应用中可以根据需求选择合适的策略,或者结合使用这两种方式。以下是详细的策略建议:

1. RDB 持久化

优点

  • RDB 通过快照机制将数据保存到磁盘上,能够在短时间内快速恢复数据。
  • RDB 文件紧凑,适合做数据备份和迁移。

缺点

  • 由于是定时快照,因此在崩溃的情况下可能会丢失最近一次快照之后的数据。
  • 大规模数据快照时,可能会影响Redis的性能。

使用建议

  • 适用于数据变化不频繁的场景。

  • 可以通过配置save参数来定时生成快照,例如:

    save 900 1   # 每15分钟如果至少有1个key发生变化,则生成快照
    save 300 10  # 每5分钟如果至少有10个key发生变化,则生成快照
    save 60 10000 # 每1分钟如果至少有10000个key发生变化,则生成快照
    
  • 使用stop-writes-on-bgsave-error确保在快照出错时停止写操作,避免数据损坏。

2. AOF 持久化

优点

  • AOF 通过记录每个写操作日志来实现数据持久化,提供更高的数据安全性。
  • 支持三种同步策略:每个写操作同步、每秒同步、操作系统控制同步,灵活性高。

缺点

  • AOF 文件相对较大,恢复时间可能较长。
  • 写操作频繁时,可能对Redis性能有一定影响。

使用建议

  • 适用于需要高数据安全性的场景。

  • 配置appendfsync参数来调整同步策略:

    appendfsync always   # 每个写操作都同步(最安全,但性能最低)
    appendfsync everysec # 每秒同步一次(折中方案,推荐使用)
    appendfsync no       # 由操作系统决定何时同步(性能最高,但可能丢失数据)
    
  • 配置no-appendfsync-on-rewrite来避免在重写AOF文件时阻塞写操作:

    no-appendfsync-on-rewrite yes
    

3. RDB 和 AOF 结合使用

策略

  • 同时启用RDB和AOF,以兼顾数据恢复速度和数据安全性。

  • 在配置文件中同时开启RDB和AOF:

    save 900 1
    save 300 10
    save 60 10000appendonly yes
    appendfsync everysec
    
  • 定期备份RDB文件,以便在AOF文件损坏时也能快速恢复数据。

4. 备份和监控

建议

  • 定期备份RDB文件和AOF文件,存储在安全的地方。
  • 使用Redis提供的INFO命令和监控工具(如Prometheus、Grafana)监控Redis性能和持久化状态。
  • 配置日志文件监控,及时发现并处理持久化过程中的异常情况。

通过以上策略,可以根据具体的应用场景和需求,选择合适的持久化机制,确保Redis在线上环境中的数据安全和高效运行。如果有具体的需求或遇到特殊问题,欢迎进一步讨论。

RDB 和 AOF 结合使用是不是线上环境最优解

在实际生产环境中,RDB 和 AOF 结合使用通常被认为是最佳实践,因为它可以同时利用两种持久化机制的优点,提供数据的安全性和较快的恢复速度。以下是两者结合使用的优点及其配置建议:

结合使用的优点

  1. 数据安全性

    • AOF 记录每个写操作日志,保证数据的持久性和完整性。在Redis意外宕机的情况下,能最大限度地减少数据丢失。
    • RDB 提供周期性的完整数据快照,便于快速恢复大量数据。
  2. 恢复速度

    • RDB 文件在数据恢复时比AOF文件更快,因为RDB文件是数据的二进制快照,而AOF需要重放所有写操作。
    • 结合使用可以在灾难恢复时先加载RDB文件,然后重放AOF日志,从而达到快速且相对完整的数据恢复效果。
  3. 性能优化

    • 定期生成RDB快照的过程中可以减小AOF文件的大小,从而降低AOF重写的开销。
    • 在进行AOF重写时,如果有RDB作为备用,可以有效降低Redis在重写期间的性能影响。

配置建议

以下是一个结合使用RDB和AOF的示例配置:

# RDB配置
save 900 1     # 每15分钟如果至少有1个key发生变化,则生成快照
save 300 10    # 每5分钟如果至少有10个key发生变化,则生成快照
save 60 10000  # 每1分钟如果至少有10000个key发生变化,则生成快照
stop-writes-on-bgsave-error yes # 快照出错时停止写操作# AOF配置
appendonly yes       # 开启AOF持久化
appendfsync everysec # 每秒同步一次,平衡性能和数据安全性
no-appendfsync-on-rewrite yes # 在AOF重写期间不进行追加同步# 其他建议
auto-aof-rewrite-percentage 100  # AOF文件增长100%时触发重写
auto-aof-rewrite-min-size 64mb   # AOF文件最小64MB时触发重写

备份和监控

  1. 定期备份

    • 定期备份RDB文件和AOF文件,并将备份存储在安全的地方(如远程存储或云存储)。
    • 备份可以通过脚本定时执行,如使用cron作业。
  2. 监控

    • 使用Redis的INFO命令监控持久化状态和性能指标。
    • 使用监控工具(如Prometheus和Grafana)可视化Redis的运行状态,设置告警机制及时发现问题。
    • 配置日志文件监控,及时处理持久化过程中可能出现的错误和异常。

通过以上策略,结合使用RDB和AOF,可以提供良好的数据持久化保障,确保在生产环境中Redis的稳定性和可靠性。如果有特殊的需求或遇到特定问题,随时可以讨论以找到更合适的解决方案。

AOF的持久化机制是如何实现的?

Redis 的 AOF(Append Only File)持久化机制通过记录每个写操作日志来实现数据的持久化。具体实现步骤如下:

1. 记录写操作

每当有写操作(如 SETLPUSHSADD 等)时,Redis 会将这个操作以命令的形式追加到 AOF 文件的末尾。每个操作都会以 Redis 命令的文本形式记录。例如:

*3
$3
SET
$3
key
$5
value

2. 同步策略

Redis 提供三种同步策略来控制 AOF 文件何时同步到磁盘:

  • always:每次写操作都立即同步到磁盘。这种方式最安全,但性能最低。
  • everysec:每秒同步一次,折衷了性能和数据安全性。
  • no:由操作系统决定何时同步,性能最好,但在系统崩溃时可能会丢失最近的写操作。

可以通过 appendfsync 参数配置同步策略:

appendfsync always
appendfsync everysec
appendfsync no

3. AOF 重写

随着时间的推移,AOF 文件会不断增长,变得非常大。为了避免文件过大,Redis 提供了 AOF 重写机制,通过创建一个新的 AOF 文件,仅包含生成当前数据集所需的最小命令集。具体步骤如下:

  1. 触发重写:当 AOF 文件增长到一定大小时(由 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 参数控制),Redis 会触发 AOF 重写。

    auto-aof-rewrite-percentage 100  # AOF 文件大小达到上次重写时的100%时触发重写
    auto-aof-rewrite-min-size 64mb   # AOF 文件最小64MB时触发重写
    
  2. 创建新文件:Redis 创建一个新的 AOF 文件,通过读取当前内存中的数据,生成最小的命令集写入新文件。这些命令集可以通过重新执行来重建当前数据集。

  3. 写操作缓冲:在重写过程中,Redis 会将新的写操作暂时缓存在内存中,确保新旧文件的一致性。

  4. 文件替换:当新文件生成完毕后,Redis 会将新的 AOF 文件替换旧的 AOF 文件,并将缓存在内存中的写操作追加到新文件中。

4. AOF 文件加载

在Redis启动时,如果配置了 AOF 持久化,Redis 会首先加载 AOF 文件中的命令来重建数据集:

  1. 读取文件:Redis 按顺序读取 AOF 文件中的命令。
  2. 重放命令:逐条执行这些命令,重建数据集。

配置示例

以下是一个典型的 AOF 配置示例:

appendonly yes             # 开启 AOF 持久化
appendfsync everysec       # 每秒同步一次
no-appendfsync-on-rewrite yes  # 在 AOF 重写期间不进行追加同步# 自动重写配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

总结

AOF 通过记录每个写操作的命令日志,确保数据持久化和可靠性。结合适当的同步策略和重写机制,AOF 提供了良好的数据安全性和性能平衡。

SpringBoot中的@Autowried 是如何注入的?

在Spring Boot中,@Autowired注解用于自动注入依赖。它是通过Spring的依赖注入(Dependency Injection,DI)机制实现的。下面详细解释其工作原理及注入过程:

1. 依赖注入概述

Spring的依赖注入有两种主要方式:

  • 构造器注入:通过类的构造函数注入依赖。
  • 属性注入:通过类的属性注入依赖。

@Autowired可以用于构造器、属性和方法来自动注入依赖。

2. @Autowired 注解的使用

  • 属性注入

    @Component
    public class MyService {@Autowiredprivate MyRepository myRepository;// other methods
    }
    
  • 构造器注入

    @Component
    public class MyService {private final MyRepository myRepository;@Autowiredpublic MyService(MyRepository myRepository) {this.myRepository = myRepository;}// other methods
    }
    
  • 方法注入

    @Component
    public class MyService {private MyRepository myRepository;@Autowiredpublic void setMyRepository(MyRepository myRepository) {this.myRepository = myRepository;}// other methods
    }
    

3. 自动注入过程

3.1. Spring 容器的初始化

当Spring容器启动时,它会扫描并实例化所有带有@Component@Service@Repository@Controller等注解的类。这些类的实例被称为Spring Bean,并被Spring容器管理。

3.2. 依赖解析

Spring容器会解析每个Bean的依赖。在解析过程中,它会检查Bean类的字段、构造器和方法上是否有@Autowired注解。

3.3. 依赖注入
  • 属性注入
    Spring容器会查找需要注入的依赖类型的Bean实例,并将其注入到带有@Autowired注解的字段中。

  • 构造器注入
    Spring容器会调用带有@Autowired注解的构造器,传递所需的依赖Bean实例。

  • 方法注入
    Spring容器会调用带有@Autowired注解的方法,传递所需的依赖Bean实例。

3.4. 处理循环依赖

Spring通过三级缓存(SingletonFactories、EarlySingletonObjects、SingletonObjects)机制解决循环依赖问题:

  1. SingletonObjects:已经完全初始化的单例对象。
  2. EarlySingletonObjects:正在创建中的单例对象,可以解决循环引用问题。
  3. SingletonFactories:用于创建单例对象的工厂,可以避免AOP代理问题。

4. 详细工作流程

  1. 扫描组件
    Spring扫描带有@Component@Service等注解的类,并将其注册为Bean。

  2. 创建Bean
    Spring按照需要创建Bean实例,并保存到三级缓存中。

  3. 依赖注入

    • Spring检查@Autowired注解。
    • 从容器中获取需要注入的Bean。
    • 将获取到的Bean注入到目标Bean中。
  4. 处理循环依赖

    • 利用三级缓存,首先创建代理对象放入缓存,然后解决依赖,最后初始化完成。

示例

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;// other methods
}@Component
public class ServiceB {@Autowiredprivate ServiceA serviceA;// other methods
}

在上述示例中,ServiceAServiceB相互依赖。Spring容器通过三级缓存机制处理这种循环依赖,确保两个Bean都能成功实例化并注入对方。

总结

@Autowired注解通过Spring的依赖注入机制,自动将所需的Bean注入到目标Bean中。Spring容器负责扫描、实例化、解析和注入依赖,确保Bean之间的依赖关系正确无误。通过三级缓存机制,Spring还能有效处理循环依赖问题。

RabbitMQ如何保证消息不丢失

RabbitMQ是一种可靠的消息队列系统,通过以下几种方式来保证消息不丢失:

1. 使用持久化消息队列(Durable Queues)

  • 配置队列为持久化:在声明队列时设置durable属性为true,确保队列在RabbitMQ服务器重启后依然存在。

    channel.queueDeclare("myQueue", true, false, false, null);
    

2. 使用持久化消息(Persistent Messages)

  • 配置消息为持久化:在发送消息时,将MessagePropertiesPERSISTENT_TEXT_PLAIN属性设置为true,确保消息在RabbitMQ服务器重启后依然存在。

    channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
    

3. 消息确认(Message Acknowledgements)

  • 启用手动消息确认:消费者在处理消息后发送确认(acknowledgement),确保消息被成功处理后再从队列中删除。

    boolean autoAck = false; // 关闭自动确认
    channel.basicConsume("myQueue", autoAck, consumerTag, new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {String message = new String(body, "UTF-8");try {// 处理消息channel.basicAck(envelope.getDeliveryTag(), false); // 手动确认消息} catch (Exception e) {channel.basicNack(envelope.getDeliveryTag(), false, true); // 处理失败时重新入队}}
    });
    

4. 发布确认(Publisher Confirms)

  • 启用发布确认模式:生产者在发送消息后等待RabbitMQ的确认,确保消息被正确写入队列。

    channel.confirmSelect(); // 启用发布确认模式channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());if (!channel.waitForConfirms()) {// 处理未确认的消息
    }
    

5. 高可用模式(High Availability)

  • 使用镜像队列(Mirrored Queues):配置队列为镜像队列,确保队列和消息在多个节点上存在副本,提高可用性和容错性。

    rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
    

6. 死信队列(Dead Letter Queues)

  • 配置死信队列:为队列设置死信交换机和死信路由键,当消息因超时或被拒绝时,消息会被转发到死信队列,以便后续处理。

    Map<String, Object> args = new HashMap<String, Object>();
    args.put("x-dead-letter-exchange", "dlx-exchange");
    args.put("x-dead-letter-routing-key", "dlx-routing-key");
    channel.queueDeclare("myQueue", true, false, false, args);
    

7. 持久化存储(Persistent Storage)

  • 使用磁盘存储消息:RabbitMQ默认将持久化消息存储在磁盘上,确保在系统崩溃时消息不会丢失。

8. 定期备份

  • 定期备份RabbitMQ数据:通过定期备份RabbitMQ的数据文件来防止数据丢失。

综合应用

为了保证消息不丢失,通常会结合以上多种方法。例如,配置持久化队列和消息、启用手动确认和发布确认、使用镜像队列和死信队列等。

配置示例

以下是一个综合使用这些方法的示例代码:

// 配置队列为持久化
channel.queueDeclare("myQueue", true, false, false, null);// 配置消息为持久化
channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());// 启用发布确认模式
channel.confirmSelect();
channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
if (!channel.waitForConfirms()) {// 处理未确认的消息
}// 启用手动消息确认
boolean autoAck = false;
channel.basicConsume("myQueue", autoAck, new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {String message = new String(body, "UTF-8");try {// 处理消息channel.basicAck(envelope.getDeliveryTag(), false);} catch (Exception e) {channel.basicNack(envelope.getDeliveryTag(), false, true);}}
});// 配置死信队列
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx-exchange");
args.put("x-dead-letter-routing-key", "dlx-routing-key");
channel.queueDeclare("myQueue", true, false, false, args);// 配置镜像队列
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}';

通过以上配置,RabbitMQ可以有效地保证消息在各种异常情况下不丢失。

如何配置一个延时队列

在RabbitMQ中配置一个延时队列可以通过使用死信交换机(Dead Letter Exchange, DLX)和消息TTL(Time-To-Live)来实现。具体步骤如下:

1. 配置延时队列和死信交换机

延时队列设置消息的TTL属性,使得消息在一定时间后到期,并被路由到死信交换机。死信交换机将消息转发到实际的处理队列。

2. 配置示例

以下是一个使用RabbitMQ Java客户端(如com.rabbitmq.client库)的示例代码:

2.1. 声明交换机和队列
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;import java.util.HashMap;
import java.util.Map;public class DelayedQueueSetup {private static final String EXCHANGE_NAME = "exchange.delayed";private static final String QUEUE_NAME = "queue.delayed";private static final String DLX_NAME = "exchange.dlx";private static final String DLX_QUEUE_NAME = "queue.dlx";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {// 声明死信交换机channel.exchangeDeclare(DLX_NAME, "direct");channel.queueDeclare(DLX_QUEUE_NAME, true, false, false, null);channel.queueBind(DLX_QUEUE_NAME, DLX_NAME, "routingKey.dlx");// 声明延时队列并绑定死信交换机Map<String, Object> args = new HashMap<>();args.put("x-dead-letter-exchange", DLX_NAME);args.put("x-dead-letter-routing-key", "routingKey.dlx");args.put("x-message-ttl", 10000); // 消息在延时队列中的存活时间(毫秒)channel.queueDeclare(QUEUE_NAME, true, false, false, args);channel.exchangeDeclare(EXCHANGE_NAME, "direct");channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingKey.delayed");// 发送消息String message = "Hello, this is a delayed message!";channel.basicPublish(EXCHANGE_NAME, "routingKey.delayed", null, message.getBytes());System.out.println(" [x] Sent '" + message + "'");// 消费消息channel.basicConsume(DLX_QUEUE_NAME, true, (consumerTag, delivery) -> {String receivedMessage = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + receivedMessage + "'");}, consumerTag -> { });}}
}

3. 配置说明

  • 声明死信交换机和死信队列

    channel.exchangeDeclare(DLX_NAME, "direct");
    channel.queueDeclare(DLX_QUEUE_NAME, true, false, false, null);
    channel.queueBind(DLX_QUEUE_NAME, DLX_NAME, "routingKey.dlx");
    
  • 声明延时队列并绑定到死信交换机

    Map<String, Object> args = new HashMap<>();
    args.put("x-dead-letter-exchange", DLX_NAME);
    args.put("x-dead-letter-routing-key", "routingKey.dlx");
    args.put("x-message-ttl", 10000); // 消息的存活时间,单位为毫秒channel.queueDeclare(QUEUE_NAME, true, false, false, args);
    channel.exchangeDeclare(EXCHANGE_NAME, "direct");
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingKey.delayed");
    
  • 发送消息到延时队列

    String message = "Hello, this is a delayed message!";
    channel.basicPublish(EXCHANGE_NAME, "routingKey.delayed", null, message.getBytes());
    
  • 消费消息
    消费从死信队列中转发的消息:

    channel.basicConsume(DLX_QUEUE_NAME, true, (consumerTag, delivery) -> {String receivedMessage = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + receivedMessage + "'");
    }, consumerTag -> { });
    

4. 运行代码

运行以上代码,将会在延时队列中发送一条消息,经过指定的TTL时间(在此示例中为10秒)后,消息会被转发到死信交换机,并最终到达实际的处理队列(死信队列)。

总结

通过使用消息的TTL和死信交换机机制,可以在RabbitMQ中轻松实现延时队列。该方法通过在消息到期后将其路由到死信交换机,实现消息的延迟处理。这种方法简单易行,且不需要额外的插件或扩展。

Mysql死锁

MySQL中的死锁是指两个或多个事务在持有某些资源的同时,等待对方持有的资源,从而形成循环等待的现象。死锁会导致这些事务无法继续执行下去,必须通过某种机制来解决。以下是MySQL中常见的导致死锁的原因、检测和解决方案。

常见的导致死锁的原因

  1. 不同顺序的锁请求

    • 如果两个事务按不同的顺序请求相同的资源,可能会导致死锁。
    • 例如,事务A先锁表T1然后锁表T2,而事务B先锁表T2然后锁表T1。
  2. 长事务

    • 长时间运行的事务持有锁的时间较长,增加了发生死锁的可能性。
  3. 大范围的更新或删除操作

    • 大范围的更新或删除操作会锁定较多的行,增加了发生死锁的可能性。
  4. 外键和触发器

    • 使用外键约束和触发器可能会导致隐式锁定,增加了发生死锁的可能性。

检测死锁

MySQL能够自动检测死锁,并回滚其中一个事务以解除死锁。可以通过以下方法来检测死锁:

  1. 通过日志文件检测

    • MySQL会将死锁信息记录到错误日志文件中,可以通过查看错误日志来检测死锁。
  2. 通过命令检测

    • 使用以下命令查看当前的InnoDB状态,其中包括死锁信息:
      SHOW ENGINE INNODB STATUS;
      
    • 输出的结果中会包含最近一次死锁的信息。

解决死锁的策略

  1. 调整事务顺序

    • 尽量使所有事务以相同的顺序请求资源,以减少死锁的可能性。
    • 例如,所有事务都先锁表T1然后锁表T2。
  2. 减少事务持有锁的时间

    • 尽量缩短事务的执行时间,避免长时间持有锁。
    • 将大事务拆分为多个小事务。
  3. 合理使用索引

    • 确保在查询中使用索引,以减少锁定的行数。
    • 尽量避免大范围的全表扫描。
  4. 捕获并处理死锁异常

    • 在应用程序中捕获并处理死锁异常,回滚被回滚的事务并重试。
    • 例如,使用Java中的Spring框架,可以配置重试机制来处理死锁。
  5. 使用合理的隔离级别

    • 在保证数据一致性的前提下,选择较低的隔离级别,如READ COMMITTED,以减少锁的争用。
    • 例如:
      SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
      

示例代码

以下是一个示例,展示如何在Java应用中使用Spring框架捕获并处理死锁异常:

import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;public class MyService {private final JdbcTemplate jdbcTemplate;public MyService(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Transactionalpublic void updateData() {boolean success = false;int retries = 3;while (!success && retries > 0) {try {// 执行数据库操作jdbcTemplate.update("UPDATE my_table SET column1 = ? WHERE column2 = ?", value1, value2);success = true;} catch (DeadlockLoserDataAccessException e) {// 捕获死锁异常并重试retries--;if (retries == 0) {throw e; // 达到重试次数,抛出异常}}}}
}

总结

MySQL中的死锁是由于事务竞争资源导致的。通过合理设计事务顺序、减少锁持有时间、使用索引、捕获并处理死锁异常,以及选择适当的隔离级别,可以有效减少和解决死锁问题。在实际应用中,结合日志和状态信息检测死锁,及时采取措施,是保障系统稳定性和性能的重要手段。

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

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

相关文章

Servlet 3.0的新特征

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhlServlet 3.0概述 Servlet 3.0规范是在2009年随着Java EE 6的发布而推出的。它引入了一系列新特性和改进,旨在简化Web应用的开发和部署过程,并提高Web应用的性能和可扩展性。Servlet 3.0的发布标…

ProGuard配置详解

ProGuard是一个开源的Java class文件缩小器、优化器、混淆器和预验证器。它通过删除未使用的类、字段、方法和属性&#xff0c;优化字节码指令&#xff0c;并重命名类、字段和方法&#xff0c;使反编译后的代码难以理解&#xff0c;从而提高应用的安全性。以下是对ProGuard配置…

大语言模型-对比学习-Contrastive Learning

一、对比学习概念 对比学习是一种特殊的无监督学习方法。 旨在通过拉近相关样本的距离并且推远不相关样本的距离&#xff0c;来学习数据表示。 通常使用一种高自由度、自定义的规则来生成正负样本。在模型预训练中有着广泛的应用。 二、对比学习小案例 对比学习主要分为三个…

Git关联本地仓库和远程仓库

Step 1 添加远程仓库: git remote add <远程仓库别名><远程仓库地址> Step 2 git push -u <远程仓库名><分支名> 查看远程仓库: git remote -v 拉取远程仓库内容: 拉取服务器仓库过程中&#xff0c;如果本地和服务器有文件冲突&#xff0c;则会拉取失…

02 MySQL数据库管理

目录 1.数据库的结构 sql语言主要由以下几部分组成 2. 数据库与表的创建和管理 1&#xff0c;创建数据库 2&#xff0c;创建表并添加数据 3&#xff0c;添加一条数据 4&#xff0c;查询数据 5&#xff0c;更新数据 6&#xff0c;删除数据 3.用户权限管理 1.创建用户 …

js轮播图制作

实现一个简单的JavaScript轮播图可以通过以下步骤完成&#xff1a; 创建HTML结构&#xff0c;包括轮播图容器和图片列表。 使用CSS进行样式设置&#xff0c;包括隐藏多余的图片。 使用JavaScript编写函数来控制图片的切换。

wsl 下执行 systemctl 报错:Failed to get D-Bus connection: Operation not permitted

2024-07-21 01:31:47 补充 经过一系列查阅&#xff0c;关键词 wsl bad performance , 虚拟机启动慢可能是因为systemd 的启动项过多或耗时长。通过 dmesg 可以打印一些系统的启动信息&#xff0c;可以看到&#xff1a; [ 1.215065] systemd-journald[59]: Received reques…

C#中栈和堆以及修饰符

关于堆中字符串的存放 string s1"123" string s2"123" string s1"456" 此时s1输出为456 而s2仍然为123 因为在使用 String str "字符串" 的方式来创建String变量的时候&#xff0c;那么String的值便会存储在String常量池中&#x…

apache.commons.pool2 使用指南

apache.commons.pool2 使用指南 为什么要使用池 创建对象耗时较长&#xff0c;多线程频繁调用等因素限制了我们不能每次使用时都重新创建对象&#xff0c;使用池化思想将对象放进池内&#xff0c;不同线程使用同一个池来获取对象&#xff0c;极大的减少每次业务的调用时间。 …

Keepalived和Haproxy

Keepalived和Haproxy 一、Keepalived 1、keepalived概念 调度器的高可用 vip地址主备之间的切换&#xff0c;主在工作时&#xff0c;vip地址值在主上&#xff0c;主停止工作&#xff0c;vip飘移到备服务器 在主备的优先级不变的情况下&#xff0c;主恢复工作&#xff0c;v…

C++——编译报重复定义错误的解决办法

原因&#xff1a; 头文件被多次编译。 解决办法&#xff1a; 找到包含头文件的地方&#xff0c;仔细检查。 比如&#xff1a; 这两句话是包含关系&#xff0c;写了第一句就不用第二句了。 因为&#xff1a;第一句是编译 tracker/detector/rknn_model_zoo/examples/yolov5/c…

【MySQL进阶之路 | 高级篇】简谈redo日志

1. 前言 事务有四种特性&#xff1a;原子性&#xff0c;一致性&#xff0c;隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢&#xff1f; 事务的隔离性由锁机制实现。而事务的原子性&#xff0c;一致性和持久性由事务的redo日志和undo日志来保证。 REDO LOG称为…

云计算实训13——DNS域名解析、ntp时间服务器配置、主从DNS配置、多区域DNS搭建

一、DNS域名解析 1.正向解析 将域名解析为IP地址 DNS正向解析核心配置 (1)安装bind [rootdns ~]# yum -y install bind (2)编辑配置文件 编辑named.conf文件&#xff0c;限定访问权限 [rootdns ~]# vim /etc/named.conf 编辑named.rfc文件&#xff0c;指定要访问的域名 [ro…

【数据结构】:用Java实现链表

在 ArrayList 任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后搬移&#xff0c;时间复杂度为 O(n)&#xff0c;效率比较低&#xff0c;因此 ArrayList 不适合做任意位置插入和删除比较多的场景。因此&#xff1a;java 集合中又引入了 LinkedList&…

Golang Gin框架部署二级目录打包的Vue前端项目小记

概述 因为最近在公司开发项目遇到一个需求 - 我们自己开发的B/S系统(以下简称&#xff1a;二级系统)作为二级子系统嵌入到三方企业的主系统&#xff0c;界面入口是主系统。经过一番折腾&#xff0c;成功实现&#xff0c;故而博文记录&#xff0c;用以备忘 可行方案 针对上述…

一步一步测试DNS隧道

目录 0、前言 1、DNS解析 1.1 DNS简介 1.2 DNS查询类型 1.3 DNS解析过程 2、DNS隧道准备工作 2.1 DNS隧道介绍 2.1.1 什么是DNS隧道&#xff1f; 2.1.2 DNS隧道的原理 2.2 客户端、服务端准备 2.3 域名准备 2.4 连接隧道 2.5 遇坑 3、隧道确认和利用…

Windows本地启动Redis

找到本地redis目录 输入cmd,然后输入redis-server.exe redis.windows.conf&#xff0c;默认端口为6379 再新打开一个cmd&#xff0c;输入redis-cli.exe -p 6379 -a &#xff08;你在redis.windows.conf中设置的密码&#xff09;

Kylin跨Cube查询:数据洞察的无限可能

Kylin跨Cube查询&#xff1a;数据洞察的无限可能 Apache Kylin是一个开源的分布式分析引擎&#xff0c;旨在为Hadoop平台提供快速的SQL查询能力。它通过预计算和存储数据立方体&#xff08;Cube&#xff09;来实现这一点。然而&#xff0c;随着数据量的增长和业务需求的多样化…

如何做好服务器的安全管理

以下是一些服务器安全防护措施&#xff1a; 1、安装杀毒软件&#xff1a;安装杀毒软件是保护服务器免受病毒和恶意软件攻击的基本措施之一。保持杀毒软件更新至最新版本&#xff0c;定期扫描检测服务器以确保其不被病毒、蠕虫等恶意软件入侵。保护服务器免受侵害。像360杀毒&am…

HarmonyOS NEXT星河版零基础入门到实战

文章目录 一、HarmonyOS NEXT介绍学习内容1、鸿蒙APP开发2、能力套件开发3、全场景开发适合人群 持续更新中✒️总结 一、HarmonyOS NEXT介绍 放弃安卓框架之后&#xff0c;HarmonyOS NEXT成为真正独立于安卓、iOS的操作系统&#xff0c;堪称是一场史无前例的脱胎换骨。在其众多…