likes
comments
collection
share

查漏补缺第八期(阿里一面)

作者站长头像
站长
· 阅读数 17

前言

目前正在出一个查漏补缺专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~

本专题主要以Java语言为主, 好了, 废话不多说直接开整吧~

聊聊Springboot与SpringCloud的区别

Spring BootSpring Cloud是两个不同的东西,它们在Java应用程序的开发和部署中扮演着不同的角色。

Spring Boot是一个用于快速构建独立的、基于Spring的应用程序的框架。它简化了Spring应用程序的配置和部署过程,通过自动配置和约定大于配置的原则,减少了开发人员的工作量。Spring Boot提供了一组开箱即用的功能和特性,例如内嵌的Web服务器、自动化配置、健康检查、监控等。使用Spring Boot,开发人员可以更快速地搭建和运行一个独立的、可执行的Spring应用程序。

Spring Cloud是构建分布式系统的工具集合,它基于Spring Boot,并提供了一系列的解决方案和组件,用于解决分布式系统中的常见问题,例如服务发现、负载均衡、配置管理、熔断器、消息总线等。Spring Cloud提供了各种功能模块,如服务注册与发现、服务调用、负载均衡、断路器、网关等,使得开发人员能够更方便地构建、部署和管理分布式微服务系统。

因此,Spring Boot主要关注于简化单个应用程序的开发和部署,而Spring Cloud则专注于构建和管理分布式系统。Spring BootSpring Cloud可以结合使用,通过使用Spring Boot创建微服务应用程序,并使用Spring Cloud提供的组件和解决方案来构建弹性和可扩展的分布式系统。

讲讲在微服务中服务的注册与发现,流程是怎样的

在微服务架构中,服务的注册与发现是实现服务间通信和动态扩展的关键机制之一。下面是一般的服务注册与发现的流程:

  1. 注册中心启动:首先,启动一个注册中心(如Eureka、Consul或Zookeeper),它负责管理所有可用的服务实例的注册信息。

  2. 服务提供者注册:当一个服务提供者(即提供某个服务的微服务)启动时,它会向注册中心发送一个注册请求,将自己的信息注册到注册中心。这些信息通常包括服务名称、IP地址、端口号、健康状态等。

  3. 服务消费者发现:当一个服务消费者(即需要调用其他服务的微服务)启动时,它会向注册中心发送一个发现请求,请求获取特定服务的可用实例列表。

  4. 注册中心返回可用实例列表:注册中心接收到服务消费者的发现请求后,会根据服务名称查找并返回可用的服务实例列表。这个列表包含了提供该服务的所有服务提供者的信息,例如IP地址和端口号。

  5. 服务消费者负载均衡:服务消费者从注册中心获取到可用实例列表后,需要选择一个具体的实例来调用。这通常使用负载均衡算法来实现,以平衡服务请求的分发,例如轮询、随机选择、权重等。

  6. 服务消费者调用服务:一旦服务消费者选择了一个服务实例,它会通过调用相应的网络协议(如HTTP或RPC)与该实例进行通信,发送请求并获取响应。

  7. 实例心跳与健康检查:注册中心会周期性地检查服务实例的健康状态,以确保只有可用的实例被返回给服务消费者。如果一个实例长时间未发送心跳或被标记为不健康,注册中心将从可用实例列表中移除它。

  8. 动态扩展和更新:在运行过程中,如果有新的服务实例启动或停止,它们会通过注册中心进行注册或注销。这使得服务的动态扩展和更新变得更加容易。

总结来说,服务注册与发现的流程包括服务提供者的注册、服务消费者的发现与负载均衡,以及注册中心的维护和健康检查。通过这个机制,微服务架构能够实现服务间的自动发现和调用,提高系统的可扩展性和弹性。

说一下SpringCloud是如何保证服务高可用的

Spring Cloud通过一系列的机制和组件来实现服务高可用。下面是一些常用的方法和技术:

  1. 服务注册与发现Spring Cloud使用服务注册与发现组件(如Eureka、Consul、Zookeeper等)来管理服务实例的注册和发现。通过将服务注册到注册中心,并通过注册中心发现可用的服务实例,可以实现服务的高可用性。当一个服务实例不可用时,注册中心会自动剔除该实例,从而避免服务消费者访问到不可用的实例。

  2. 负载均衡Spring Cloud支持多种负载均衡策略,如基于权重的负载均衡、轮询随机选择等。通过在服务消费者中配置适当的负载均衡策略,可以将请求均衡地分发到多个可用的服务实例上,从而提高系统的可用性和性能。

  3. 熔断器Spring Cloud集成了熔断器模式,通过使用Hystrix等熔断器框架,可以实现对服务调用的容错降级处理。当服务发生故障或超时时,熔断器可以快速失败,并返回预定义的降级响应,避免级联故障和服务雪崩效应,提高整个系统的可用性。

  4. 高可用配置中心:Spring Cloud提供了分布式配置中心(如Spring Cloud Config),它可以集中管理应用程序的配置信息。通过将配置信息集中存储在配置中心,并在应用程序启动时从配置中心获取最新的配置,可以避免配置信息的分散和不一致,从而提高配置的可用性和一致性。

  5. 服务容错和降级Spring Cloud还支持通过服务容错和降级来保证系统的高可用性。通过使用断路器模式、服务降级策略和容错机制,可以在服务故障或不可用时保证系统的稳定运行,避免故障的扩散和影响其他服务。

  6. 高可用消息队列:使用消息队列作为服务间的异步通信机制,可以提高系统的可用性和弹性。Spring Cloud支持多个消息中间件(如RabbitMQ、Kafka),通过将消息发布到消息队列中,实现服务之间的解耦和异步通信,以应对高并发和故障情况。

综上所述,Spring Cloud通过服务注册与发现、负载均衡、熔断器、配置中心、服务容错和降级等一系列的机制和组件,来保证服务的高可用性。这些技术可以帮助构建弹性和可靠的分布式系统,提高系统的可用性、可扩展性和稳定性。

分布式系统中如何保证Redis高可用

在分布式系统中,可以采取以下策略来保证Redis的高可用性:

  1. 主从复制:通过设置Redis的主从复制机制,将主节点的数据实时复制到多个从节点。当主节点发生故障或不可用时,可以快速切换到其中一个从节点作为新的主节点,保证系统的可用性。主从复制还可以提高读取性能,因为从节点可以处理读取请求,减轻主节点的负载。

  2. 哨兵模式Redis Sentinel(哨兵)Redis官方提供的高可用性解决方案。哨兵模式通过运行多个哨兵节点来监控Redis的主从状态,并在主节点不可用时自动进行故障转移。哨兵节点会选举一个新的主节点,并通知其他从节点切换到新的主节点,从而保证系统的高可用性。

  3. Redis ClusterRedis ClusterRedis官方提供的分布式解决方案。它通过将数据分布在多个节点上,并使用哈希槽(hash slot)来管理数据的分片和路由。每个节点负责处理一部分哈希槽的数据。当某个节点不可用时,其他节点可以继续提供服务。Redis Cluster提供了自动的故障转移和数据迁移机制,可以保证系统的可用性和数据一致性。

  4. 数据持久化Redis支持RDB(快照)AOF(日志)两种持久化机制。使用持久化机制可以将数据写入磁盘,以防止数据丢失。在故障恢复时,可以使用持久化文件来还原数据。

  5. 监控和报警:设置监控系统来实时监测Redis的运行状态,包括内存使用情况、连接数、CPU利用率等。通过监控系统可以及时发现潜在的故障和性能问题,并及时采取相应的措施。同时,设置报警机制,当Redis出现异常情况时,及时通知相关人员进行处理。

  6. 容灾和备份:定期进行Redis数据的备份,并将备份数据存储在不同的地理位置或存储介质中,以防止数据丢失。在灾难恢复时,可以使用备份数据来还原Redis的状态。

说说Java8中有哪些垃圾回收机制

Java 8中,主要使用了以下几种垃圾回收机制:

  1. 标记-清除算法(Mark and Sweep):标记-清除算法是最基础的垃圾回收算法之一。它通过标记阶段识别出所有活跃对象,并在清除阶段回收未标记的对象。标记-清除算法有一个明显的缺点是会产生大量的内存碎片。

  2. 复制算法(Copying):复制算法将内存分为两个区域,通常称为Eden区和Survivor区。在垃圾回收过程中,将活跃对象复制到Survivor区,并清理Eden区和Survivor区中的垃圾。复制算法的优点是可以快速回收垃圾,但缺点是需要额外的内存空间来进行对象复制。

  3. 标记-压缩算法(Mark and Compact):标记-压缩算法结合了标记-清除算法和复制算法的思想。首先,标记出所有活跃对象,然后将它们向一端移动,最终清理掉未标记的对象。标记-压缩算法解决了标记-清除算法的内存碎片问题,但需要额外的时间来进行内存压缩。

  4. 并行垃圾回收(Parallel Garbage Collection):并行垃圾回收使用多个线程并行进行垃圾回收操作。它可以充分利用多核处理器的优势,加快垃圾回收的速度。并行垃圾回收通常适用于大型的堆内存和多核的服务器环境。

  5. CMS(Concurrent Mark Sweep)算法:CMS算法是一种以最短停顿时间为目标的垃圾回收算法。它通过并发标记和并发清理的方式,在尽可能短的时间内完成垃圾回收。CMS算法适用于响应时间要求较高的应用场景,但在执行过程中可能会产生碎片。

  6. G1(Garbage-First)算法G1算法是Java 8引入的一种垃圾回收算法。它将堆内存划分为多个区域(Region),并根据垃圾对象的分布情况,优先回收垃圾最多的区域。G1算法旨在平衡吞吐量停顿时间的需求,适用于大内存和低延迟要求的应用。

说说分布式锁的应用,你是如何实现的

分布式锁是一种用于在分布式系统中实现互斥访问的机制。它可以确保在多个节点上的并发操作中,只有一个节点能够获得锁并执行关键代码,其他节点需要等待或尝试重新获取锁。以下是几种实现分布式锁的常见技术和方法:

  1. 基于数据库的实现:通过在数据库中创建一个唯一索引或唯一约束来实现分布式锁。只有一个节点能够成功插入该记录,其他节点会因为冲突而失败。下面是一个基于MySQL数据库的简单示例:
public boolean tryAcquireLock(String lockKey) {
    try (Connection connection = dataSource.getConnection();
         PreparedStatement statement = connection.prepareStatement("INSERT INTO locks (lock_key) VALUES (?)")) {
        statement.setString(1, lockKey);
        int rowsAffected = statement.executeUpdate();
        return rowsAffected == 1;
    } catch (SQLException e) {
        // 处理异常
    }
    return false;
}

public void releaseLock(String lockKey) {
    try (Connection connection = dataSource.getConnection();
         PreparedStatement statement = connection.prepareStatement("DELETE FROM locks WHERE lock_key = ?")) {
        statement.setString(1, lockKey);
        statement.executeUpdate();
    } catch (SQLException e) {
        // 处理异常
    }
}
  1. 基于缓存的实现:使用分布式缓存(如Redis、Memcached)来实现分布式锁。通过在缓存中设置一个键值对,其中键是的唯一标识,值可以是任意值或当前节点的标识。只有一个节点能够成功设置该键值对,其他节点尝试获取锁时会失败。下面是一个基于Redis的示例:
public boolean tryAcquireLock(String lockKey, String nodeId, int expireSeconds) {
    try (Jedis jedis = jedisPool.getResource()) {
        String result = jedis.set(lockKey, nodeId, "NX", "EX", expireSeconds);
        return "OK".equals(result);
    } catch (Exception e) {
        // 处理异常
    }
    return false;
}

public void releaseLock(String lockKey, String nodeId) {
    try (Jedis jedis = jedisPool.getResource()) {
        String currentLockOwner = jedis.get(lockKey);
        if (nodeId.equals(currentLockOwner)) {
            jedis.del(lockKey);
        }
    } catch (Exception e) {
        // 处理异常
    }
}
  1. 基于ZooKeeper的实现:使用ZooKeeper来实现分布式锁。通过创建一个有序的临时节点,节点的序号代表获取锁的顺序。只有序号最小的节点能够获取锁,其他节点需要监听前一个节点的删除事件以尝试获取锁。下面是一个基于ZooKeeper的示例:
public boolean tryAcquireLock(String lockPath) {
    try {
        String nodePath = zooKeeper.create(lockPath + "/lock-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        List<String> children = zooKeeper.getChildren(lockPath, false);
        Collections.sort(children);
        String smallestNode = children.get(0);
        return nodePath.endsWith(smallestNode);
    } catch (KeeperException | InterruptedException e) {
        // 处理异常
    }
    return false;
}

public void releaseLock(String lockPath) {
    try {
        zooKeeper.delete(lockPath, -1);
    } catch (KeeperException | InterruptedException e) {
        // 处理异常
    }
}

以上是几种常见的分布式锁实现方法,每种方法都有其优劣和适用场景。在实际应用中,需要根据具体的需求和系统环境选择合适的分布式锁技术。感兴趣的小伙伴可以继续研究一些其它的实现方式~

结束语

大家可以针对自己薄弱的地方进行复习, 然后多总结,形成自己的理解,不要去背~

本着把自己知道的都告诉大家,如果本文对您有所帮助,点赞+关注鼓励一下呗~

相关文章

项目源码(源码已更新 欢迎star⭐️)

往期设计模式相关文章

设计模式项目源码(源码已更新 欢迎star⭐️)

Kafka 专题学习

项目源码(源码已更新 欢迎star⭐️)

ElasticSearch 专题学习

项目源码(源码已更新 欢迎star⭐️)

往期并发编程内容推荐

推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

博客(阅读体验较佳)