当前位置: 首页 > article >正文

【后端开发面试题】每日 3 题(八)

✍个人博客:Pandaconda-CSDN博客
📣专栏地址:https://blog.csdn.net/newin2020/category_12903849.html
📚专栏简介:在这个专栏中,我将会分享后端开发面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

1. 简述负载均衡的概念、常见算法及其在后端开发中的应用场景

  • 概念:负载均衡是一种将工作负载分布到多个计算资源(如服务器、数据库等)上的技术,旨在优化资源使用、最大化吞吐量、减少响应时间,并避免单个资源过载。通过负载均衡,可以提高系统的可用性、可靠性和性能。
  • 常见算法
    • 轮询算法(Round Robin):按照顺序依次将请求分配给后端服务器,每个服务器在一次循环中处理一个请求。优点是实现简单,缺点是不考虑服务器的实际负载情况。
    • 加权轮询算法(Weighted Round Robin):为每个服务器分配一个权重,权重高的服务器会处理更多的请求。可以根据服务器的硬件配置、性能等因素来设置权重,更合理地分配负载。
    • 随机算法(Random):随机选择一个后端服务器来处理请求。这种算法简单,但同样没有考虑服务器的负载情况。
    • 加权随机算法(Weighted Random):结合了随机算法和加权的思想,根据服务器的权重随机选择服务器,权重高的服务器被选中的概率更大。
    • 最少连接算法(Least Connections):将请求分配给当前连接数最少的服务器,能更好地平衡服务器的负载,因为连接数少的服务器通常负载较轻。
    • IP 哈希算法(IP Hash):根据客户端的 IP 地址进行哈希计算,将相同 IP 地址的请求始终分配到同一台服务器上。适用于需要保持会话一致性的场景。
  • 应用场景
    • Web 服务器集群:在大型网站中,将用户的 HTTP 请求通过负载均衡器分发到多个 Web 服务器上,提高网站的并发处理能力和响应速度。
    • 数据库集群:对于数据库读写分离的架构,使用负载均衡器将读请求分发到多个从数据库服务器上,减轻主数据库的读压力。
    • 分布式系统:在微服务架构中,负载均衡器可以将客户端的请求分发到多个微服务实例上,实现服务的高可用和弹性伸缩。

2. 在 Java 中,如何实现线程池?

在 Java 中,可以通过 java.util.concurrent 包下的 ThreadPoolExecutor 类或其提供的工厂方法来实现线程池。以下是几种常见的实现方式:

  • 使用 Executors 工厂类创建线程池
    • 固定大小线程池(FixedThreadPool):创建一个固定大小的线程池,线程池中的线程数量始终保持不变。
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class FixedThreadPoolExample {
        public static void main(String[] args) {
            // 创建一个固定大小为 3 的线程池
            ExecutorService executor = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 5; i++) {
                final int taskId = i;
                executor.submit(() -> {
                    System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
            executor.shutdown();
        }
    }
    
  • 单线程线程池(SingleThreadExecutor):创建一个只有一个线程的线程池,任务会按照提交的顺序依次执行。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        // 创建一个单线程线程池
        ExecutorService executor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}
  • 缓存线程池(CachedThreadPool):创建一个可缓存的线程池,如果线程池中的线程在 60 秒内没有被使用,会被自动回收;当有新任务提交时,如果没有可用线程,会创建新的线程。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个缓存线程池
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}
  • 手动创建 ThreadPoolExecutor 线程池
import java.util.concurrent.*;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        // 手动创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                5, // 最大线程数
                60, // 线程空闲时间
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10) // 任务队列
        );
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

3. 在 MongoDB 中,如何进行数据的备份和恢复?

  • 备份
    • 使用 mongodump 工具:mongodump 是 MongoDB 自带的备份工具,可用于备份整个数据库、指定数据库或指定集合。
      • 备份整个 MongoDB 实例:
mongodump --host <hostname> --port <port> --out <backup_directory>

其中, 是 MongoDB 服务器的主机名, 是端口号,<backup_directory> 是备份文件存储的目录。

  • 备份指定数据库:
mongodump --host <hostname> --port <port> --db <database_name> --out <backup_directory>
  • 备份指定集合:
mongodump --host <hostname> --port <port> --db <database_name> --collection <collection_name> --out <backup_directory>
  • 使用 MongoDB Atlas 备份功能(云服务):如果使用 MongoDB Atlas 云服务,它提供了自动备份和快照功能,可以根据需要设置备份策略,如每天、每周备份等。
  • 恢复
    • 使用 mongorestore 工具:mongorestore 用于将 mongodump 生成的备份文件恢复到 MongoDB 中。
      • 恢复整个备份:
mongorestore --host <hostname> --port <port> <backup_directory>
  • 恢复指定集合:
mongorestore --host <hostname> --port <port> --db <database_name> --collection <collection_name> <backup_directory>/<database_name>/<collection_name>.bson

在恢复数据时,需要注意目标数据库的状态和权限,确保有足够的权限进行恢复操作。同时,如果备份文件是加密的,需要提供相应的解密密钥。


http://www.kler.cn/a/577072.html

相关文章:

  • ‌工业智能网关,七大领域驱动数智化升级
  • 使用 ResponseBodyEmitter 实现异步响应式数据流处理
  • Intent3D
  • 《实战AI智能体》Deepseek可以做什么?自然语言理解与分析
  • 计算机网络——交换机
  • golang坐标转换 gomap3d库
  • Flink之Barrier对齐会影响执行效率,怎么跳过Barrier对齐,跳过后还能保证‌Exactly-Once语义吗?
  • 阿里云服务器监控
  • UniApp 运行的微信小程序如何进行深度优化
  • MapReduce:分布式计算的基石
  • Django模型使用和前后端交互
  • 每天五分钟深度学习PyTorch:向更深的卷积神经网络挑战的ResNet
  • Android 检查更新
  • 如果布隆过滤器挂了,里边存的数据全丢失了,怎么恢复呢?
  • Jmeter进行http接口测试详解
  • Java 大视界 -- Java 大数据在智能家居能源管理与节能优化中的应用(120)
  • C语言基础系列【20】内存管理
  • Pico 4 Enterprise(企业版)与Unity的交互-打包运行及UI交互篇
  • C++25--lambda表达式
  • 51 单片机中断控制寄存器 TCON