微服务相关问题及答案(2024)

1、什么是微服务?

微服务是一种软件架构风格,其中应用程序被构建为一系列小型、独立的服务单元,每个服务运行在自己的进程中,并通常围绕业务能力进行组织。每个服务为特定的业务目标提供模块化的功能,并通过定义良好的API与其他服务通信。

这些服务可以用不同的编程语言编写,可以独立地部署在各种环境中,包括云平台。微服务架构使得大型、复杂的应用程序可以被拆分成易于管理和理解的小块,提高了可扩展性、灵活性和维护性。

在微服务架构中,每个服务通常拥有自己的数据存储,确保了服务的独立性和松耦合。这种方式有助于团队独立地开发、测试、部署和扩展各个服务。此外,这种架构也支持持续交付和部署的实践,使得新功能和更新可以快速且频繁地推出。

2、微服务的优点和缺点是什么?

微服务架构带来了一系列的优点和挑战。下面详细列出了这些优点和缺点:

微服务的优点:

  1. 灵活性和敏捷性:

    • 微服务允许团队独立地更新和部署服务,这加速了开发和上市时间。
    • 可以用多种不同的语言和技术栈来开发服务。
  2. 可扩展性:

    • 可以根据需求对单个服务进行扩展,而不必扩展整个应用程序。
  3. 容错性:

    • 服务独立部署有助于局部化故障,避免全系统的中断。
  4. 可维护性和可测试性:

    • 服务小而专注,更容易理解和维护。
    • 可以单独测试每个服务,而不是整个应用程序。
  5. 解耦合:

    • 服务之间通信的清晰界限有助于减少依赖性。
  6. 多团队协作:

    • 不同团队可以在不同服务上独立工作,提高了开发效率。

微服务的缺点:

  1. 复杂性增加:

    • 分布式系统的设计、部署和管理要比单体应用复杂得多。
    • 系统间的通信可能导致性能问题和复杂的错误处理。
  2. 数据一致性:

    • 数据分散在不同的服务中,要实现数据的一致性比较困难。
  3. 测试难度:

    • 测试分布式系统可能比单体应用更复杂,涉及到服务间的交互。
  4. 部署复杂性:

    • 需要更复杂的部署流程来处理不同服务之间的依赖性。
  5. 开发和运维成本:

    • 需要专门的运维工具和流程来监控和支持分布式服务。
    • 开发人员需要考虑网络延迟、消息序列化和反序列化等。
  6. 网络延迟:

    • 服务间通信可能增加额外的网络延迟。
  7. 安全性:

    • 更多的服务意味着可能有更多的安全漏洞。

对于大型企业和需要快速发展和维护的应用来说,微服务提供了极大的灵活性和可扩展性。然而,对于小型团队或者初创企业来说,微服务带来的复杂性和运维开销可能是一个考量因素。遵循最佳实践和使用适当的工具可以帮助抵消一些这些缺点。

3、如何设计一个微服务系统?

设计一个微服务系统涉及对系统架构的全面理解,以及对业务需求、数据一致性、服务间通信、容错能力、监控和安全性等方面的深入考虑。以下是设计微服务系统时需要遵循的步骤和最佳实践:

1. 定义业务域

  • 领域驱动设计(DDD): 使用领域驱动设计来识别业务域和子域,确保每个微服务围绕特定的业务功能构建。
  • 服务边界: 确定服务的边界,确保每个服务是自包含的,并且有明确的职责。

2. 选择合适的技术栈

  • 语言和框架: 根据每个服务的需要选择适当的编程语言和框架。
  • 数据库: 选择适合服务需求的数据库,可以是SQL或NoSQL,服务可以有自己的私有数据库。

3. 设计服务API

  • RESTful API: 设计清晰、一致的RESTful接口或使用GraphQL。
  • 版本控制: 为API设计一种版本控制策略,以便在不破坏现有客户端的情况下进行迭代。

4. 保证数据一致性

  • 数据库事务: 确保数据库事务在单个服务内部处理。
  • 数据一致性策略: 如果需要跨服务处理事务,使用最终一致性模型或分布式事务模式,如Saga。

5. 微服务间的通信机制

  • 同步通信: REST或gRPC可以用于服务间的同步调用。
  • 异步通信: 使用消息队列或事件总线来实现服务间的异步通信。

6. 安全性设计

  • 身份验证和授权: 使用OAuth、JWT等机制来保护服务。
  • 服务间通信安全: 确保服务间的通信是安全的,使用TLS等机制。

7. 容错能力

  • 超时和重试机制: 为网络请求实现超时和重试策略。
  • 断路器: 使用断路器模式来防止级联故障。
  • 限流: 实现限流策略以防止服务被过度使用。

8. 部署和运维

  • 容器化: 使用容器技术(Docker)来封装服务。
  • 编排: 使用Kubernetes等工具来管理容器生命周期。
  • 监控和日志: 实施全面的监控和日志记录,以快速定位问题。

9. 自动化和CI/CD

  • 持续集成/持续部署: 建立自动化的CI/CD流程来加速开发和部署。

10. 测试策略

  • 单元测试: 确保每个服务都有充分的单元测试。
  • 集成测试: 实施自动化的集成测试来测试服务间的交互。
  • 端到端测试: 进行端到端测试来验证整个系统的行为。

11. 文档和团队沟通

  • 文档: 提供详细的API文档和架构文档。
  • 团队沟通: 在团队间建立良好的沟通方式,确保架构决策和变更被共享。

设计微服务系统是一项复杂的任务,需要根据具体的业务场景和技术环境进行调整。在设计过程中,务必要保持系统的灵活性,以适应业务的快速变化和技术的演进。

4、微服务之间如何通信?

微服务之间的通信是微服务架构中的一个核心组成部分,它确保了服务能够交换数据并协作完成任务。通信机制通常分为同步和异步两种方式。

同步通信

  1. HTTP/REST: 微服务之间可以通过RESTful API进行通信。这种方式使用HTTP作为传输协议,通常利用JSON或者XML作为数据交换格式。

  2. gRPC: gRPC是一个高性能的RPC(远程过程调用)框架,它使用Protocol Buffers作为接口定义语言,并且默认使用HTTP/2作为传输协议。gRPC适合需要高效通信和强类型接口的场景。

  3. GraphQL: GraphQL是一种为API而生的查询语言,允许客户端明确地指定它们需要哪些数据,这可以减少网络请求的数量和大小。

异步通信

  1. 消息队列: 微服务可以使用消息队列(如RabbitMQ、Apache Kafka、Amazon SQS等)来实现异步通信。这种方式允许服务发布消息而无需等待直接的响应。

  2. 事件总线: 在基于事件驱动的架构中,服务通过事件总线进行通信,这涉及到发布/订阅模型。服务发布事件到总线,其他服务订阅这些事件并响应。

  3. WebSockets: 当需要双向实时通信时,WebSockets是一个很好的选择。这允许服务之间保持长时间的连接,并实时交换消息。

服务网格

服务网格如Istio、Linkerd等,提供了微服务之间通信的基础设施层。它们可以帮助管理服务发现、负载均衡、故障恢复、指标和监控,以及更复杂的操作如A/B测试、金丝雀发布和访问控制。

选择正确的通信策略

选择哪种通信机制取决于具体的应用场景。例如,如果服务需要实时响应,同步通信可能是更好的选择。如果服务需要处理高负载或保持解耦合,异步通信可能更为适宜。通常情况下,大型系统可能同时使用多种通信模式,以满足不同服务之间的不同通信需求。

同步和异步通信的优缺点

同步和异步通信是微服务架构中常用的两种通信方式,每种方式都有其特定的使用场景和优缺点。

同步通信

优点:
  1. 直观易懂: 同步通信模式通常是阻塞的,这意味着调用一个服务并等待响应,直到操作完成。这种请求-响应模式对于开发者来说很直观。
  2. 即时性: 对于需要即时响应的操作,同步通信提供了及时的反馈。
  3. 简单的错误处理: 错误可以在请求的上下文中直接返回和处理。
  4. 请求驱动: 理想用于直接的客户端到服务器的交互,其中客户端需要对操作的结果有即时反馈。
缺点:
  1. 紧耦合: 发起请求的服务通常需要知道被调用服务的位置和协议,这可能导致服务之间的紧密耦合。
  2. 容错性较低: 如果被调用的服务不可用,发起请求的服务将无法继续执行,可能导致系统整体不稳定。
  3. 性能瓶颈: 同步调用可能会阻塞调用者,导致性能瓶颈,尤其是在高负载情况下。
  4. 可扩展性限制: 对于高吞吐量的应用,管理和维护所有同步请求可能会变得复杂和困难。

异步通信

优点:
  1. 解耦合: 异步通信允许服务间通信而无需彼此了解,只需通过共享的消息系统进行交互,减少了耦合。
  2. 高容错性: 一个服务的失败不会立即影响到调用者,因为消息可以在消息系统中排队,直到可以被处理。
  3. 扩展性强: 通过异步处理,系统可以更容易地扩展,可以通过添加更多的处理者来处理增加的消息负载。
  4. 资源利用效率: 异步处理允许调用者不必等待响应而继续其他工作,从而更有效地利用资源。
缺点:
  1. 复杂的错误处理: 异步通信中,错误处理和重试逻辑需要更加复杂的机制来管理。
  2. 延迟的反馈: 如果系统需要提供即时反馈给用户,异步通信可能并不合适,因为操作的结果可能会有延迟。
  3. 跟踪难度: 跟踪异步请求的路径比同步请求的路径要复杂,这会使得调试和监控更加困难。
  4. 消息一致性: 确保分布式系统中消息的顺序和状态一致性可以是一个挑战。

在实际应用中,同步和异步通信往往会根据具体的业务需求和技术场景混合使用。比如在用户界面的交互中采用同步通信以确保良好的用户体验,而在后端服务处理耗时任务时采用异步通信来提高系统的吞吐量和可靠性。

5、什么是服务发现?

服务发现是分布式系统中的一个关键组件,尤其是在微服务架构中至关重要。它指的是在一个动态变化的网络环境中,服务能够自动找到网络中其他服务实例的过程。

在传统的单体应用中,各个模块通常是在同一个本地环境内部进行交互,所以会话和通信管理相对简单。然而,在微服务架构中,应用被拆分成许多独立的服务,这些服务可能部署在不同的服务器、容器或者是平台上。随着系统的扩展,服务实例可能会增加或减少,它们的位置(即IP地址和端口)也可能会变化。服务发现的目的是让这些服务能够彼此发现并进行通信,而无需硬编码服务的位置。

服务发现通常有两种模式:

客户端发现模式

在客户端发现模式中,客户端服务会查询一个服务注册表,该注册表有一个服务实例的列表及其位置。然后,客户端使用这些信息来直接与服务实例进行通信。这个模式要求客户端知道如何查询注册表以及如何使用这些信息来路由请求。

服务器端发现模式

在服务器端发现模式中,客户端会发送请求到一个服务路由器(通常是一个负载均衡器),该路由器负责查询服务注册表,并将请求转发到合适的服务实例。这种方式下,客户端不需要知道服务实例的位置或者服务注册表的细节。

无论哪种模式,服务注册过程都至关重要。服务实例在启动时会向服务注册表注册自己,告知其可用性。如果服务实例变得不可用,它需要从注册表中撤销注册,或者注册表需要能够通过健康检查机制自动去除不健康的服务实例。

举例来说,当新的微服务实例启动时,它会向服务注册中心如Consul、Eureka或Zookeeper等注册自己的地址信息。当其他服务需要与此服务通信时,它们会查询服务注册中心以获取当前可用的服务实例列表,然后根据需要与其中的实例建立通信。

服务发现机制对于确保微服务架构的高可用性和弹性至关重要,因为它允许服务即使在频繁的部署和扩展操作中也能够保持互联互通。

6、如何处理微服务的数据库?

在微服务架构中处理数据库的策略和考虑因素通常比传统的单体应用复杂得多,因为数据库需要与服务的分布式和独立特性相协调。下面是一些处理微服务数据库的常见方法和最佳实践:

数据库策略

  1. 数据库每服务(Database per Service):

    • 每个微服务拥有自己的数据库实例或模式。
    • 服务完全控制其数据模型和数据存储机制。
    • 可以根据服务特定的需求选择数据库类型,比如关系型、NoSQL或图形数据库等。
  2. 共享数据库:

    • 多个服务共享同一个数据库实例,但通常情况下,每个服务拥有自己的表集合。
    • 这种方式容易实现,但随着时间推移可能导致服务间耦合增加。
    • 通常不推荐使用,除非是出于遗留系统迁移的临时策略。
  3. 服务集成:

    • 服务通过API调用而不是直接数据库连接来交互数据。
    • 促进服务之间的松耦合和数据的一致性。
  4. Serverless 数据库:

    • 使用云服务提供的数据库服务,如AWS的Aurora Serverless或Google Cloud的Firestore。
    • 数据库基础设施的管理由云提供商处理,简化了操作负担。

数据管理最佳实践

  1. 事务管理:

    • 在单个微服务内保持事务一致性。
    • 通过分布式事务模式(如SAGA)来处理跨服务的事务。
  2. 数据一致性:

    • 实现最终一致性,而非强一致性,使用事件驱动的方法来同步不同服务的数据变化。
    • 采用领域驱动设计(DDD)来定义边界上下文,从而减少服务之间的数据依赖。
  3. 数据迁移:

    • 使用数据库版本控制工具(如Flyway或Liquibase)来管理数据库模式的变更和迁移。
    • 确保数据库迁移可以自动化并且与服务的部署流程集成。
  4. 数据备份和恢复:

    • 定期备份数据,并确保恢复流程的有效性和可靠性。
    • 根据业务需求和合规性要求制定备份策略。
  5. 性能和优化:

    • 对数据库进行监控和调优,以确保性能满足服务的需求。
    • 应用缓存策略来减少对数据库的直接访问,改善响应时间。
  6. 安全性:

    • 实现适当的安全机制,如加密、访问控制和审计。
  7. 多租户支持:

    • 如果需要支持多租户,设计数据库模式以有效隔离不同租户的数据。

挑战

  • 数据的整合与分析: 将分散于各个服务中的数据集中起来进行分析和报告可能比较困难。
  • 数据迁移和变更管理: 在服务独立演化的情况下,管理数据库模式的变更需要更多的协调工作。
  • 跨服务的数据一致性: 在没有共享数据库的情况下,确保数据在服务之间保持一致性是一个挑战。

处理微服务的数据库需要根据特定的业务需求、团队能力和系统复杂度来制定策略,并且可能需要随着时间的推移和系统的演进而不断调整和优化。

7、如何确保微服务的安全性?

确保微服务安全性是构建可靠系统的关键要素之一。由于微服务架构涉及多个服务之间的分散交互,因此它们可能面临多方面的安全威胁。以下是确保微服务安全性的一些策略和最佳实践:

身份认证和授权

  1. 中央身份认证服务:

    • 使用OAuth2.0、OpenID Connect等标准协议。
    • 通过一个中央认证服务进行用户认证,并生成令牌。
  2. 服务到服务的认证:

    • 确保服务间的通信使用相互TLS(mTLS)等机制进行安全验证。
  3. 细粒度的授权:

    • 使用角色基础访问控制(RBAC)或属性基访问控制(ABAC)等模型对服务进行细粒度授权。
  4. API网关:

    • 使用API网关管理公共API的访问,实施认证和授权策略。

网络安全

  1. 网络隔离:

    • 使用虚拟网络或服务网格来隔离服务,以限制服务间的通信。
  2. 防火墙与安全组:

    • 在服务之间施加防火墙规则和安全组策略,确保只有授权的服务可以通信。
  3. 限制流量:

    • 通过限制对服务的流量可以减少DDoS攻击的风险。

加密

  1. 传输层加密:

    • 所有服务间通信应使用HTTPS或其他加密协议。
  2. 数据加密:

    • 在存储和传输时对敏感数据进行加密。

安全编码实践

  1. 输入验证:

    • 对所有服务的输入进行验证,防止SQL注入、跨站脚本(XSS)等攻击。
  2. 依赖性管理:

    • 定期更新依赖库,修复已知的安全漏洞。

日志和监控

  1. 安全审计:

    • 记录所有服务间的交云日志,以便进行安全审计和异常检测。
  2. 异常检测:

    • 实施实时监控系统来检测和警报可疑活动。

安全测试与合规

  1. 自动化测试:

    • 实施自动化的安全测试,如静态代码分析(SAST)、动态应用程序安全测试(DAST)等。
  2. 合规性检查:

    • 确保所有服务都遵守相关的安全标准和法规要求(如GDPR、HIPAA等)。

安全设计

  1. 最小权限原则:

    • 服务应该运行在最小权限模式,只有完成其功能所必需的权限。
  2. 服务故障隔离:

    • 设计服务和部署策略以便在服务受到攻击时能够隔离影响。

人员和流程

  1. 安全意识培训:

    • 对开发人员、操作人员进行定期的安全培训。
  2. 安全流程:

    • 建立和维护适当的安全事故响应流程。

确保微服务安全需要在设计、开发、部署和运营的每一个环节都采取恰当的安全措施。这些措施的实施通常需要多学科的协作,包括开发、运维和安全团队的紧密合作。

8、你熟悉哪些微服务框架?

微服务框架提供了一系列的工具和功能,以帮助开发者设计、开发、部署和管理微服务架构。随着微服务概念的普及,出现了多种不同的框架来支持微服务的开发。以下是一些流行的微服务框架:

  1. Spring Boot 和 Spring Cloud:

    • 由Pivotal团队开发,Spring Boot简化了基于Spring的应用程序的创建和部署,而Spring Cloud提供了一系列模式的实现,比如配置管理、服务发现、断路器等。
    • 这是Java生态系统中最流行的微服务框架之一。
  2. Express.js 和 NestJS(针对Node.js):

    • Express.js 是一个灵活的Node.js Web应用程序框架,提供了一系列强大的功能,为构建单页面、多页面以及混合Web应用提供了固体的基础。
    • NestJS是建立在Express.js之上的一个框架,它提供了一个可扩展的架构,支持TypeScript,非常适合用来构建高效可靠的服务器端应用程序。
  3. Flask 和 Django(针对Python):

    • Flask是一个微型的Web框架,它灵活且轻量级,适合微服务开发。
    • Django可以通过Django REST framework进行RESTful API的开发,尽管它通常用于更传统的单体应用程序。
  4. Go Micro:

    • Go Micro是一个插件驱动的微服务框架,专为Go语言设计。它使用了RPC为通信模式,并提供了服务发现、负载均衡、同步和异步通信等功能。
  5. Micronaut:

    • Micronaut是一个现代的、JVM-based的全栈微服务框架,用于构建模块化、轻量级的服务。它的启动时间快,占用内存小,适合构建微服务和无服务器应用程序。
  6. Lagom:

    • Lagom是一个专为微服务开发设计的框架,由Lightbend提供,专注于Java和Scala语言。它鼓励采用领域驱动设计(DDD)的原则来构建响应式的微服务。
  7. Akka:

    • Akka是一个用于构建高并发、分布式和容错应用的工具集。虽然它不是一个微服务框架,但是Akka系统可以作为微服务的基础。
  8. Helidon:

    • Oracle推出的Helidon是一个Java微服务框架,提供了两个版本:Helidon SE和Helidon MP。Helidon SE提供了一个轻量级的函数式编程模型,而Helidon MP是一个MicroProfile的实现。
  9. Quarkus:

    • Quarkus是为现代云原生应用设计的Kubernetes原生Java框架,专注于开发效率和轻量级的运行时。

这些框架各有千秋,选择哪个框架取决于具体的项目需求、团队的技术栈以及对性能和规模的考量。通常,框架的选择应当支持快速开发、容易维护、可扩展且能够整合现代云技术。

9、如何监控和记录微服务?

监控和记录(日志)微服务对于保证系统的健康、性能和可靠性至关重要。随着微服务架构的复杂性增加,实施有效的监控和日志记录策略就显得更加重要了。以下是一些监控和记录微服务的最佳实践:

监控微服务

  1. 中央化监控平台:

    • 使用如Prometheus、Datadog、New Relic等工具来收集和展示各个微服务的度量信息。
  2. 健康检查端点:

    • 为每个微服务提供一个健康检查API,以便监控系统能够定期检查服务状态。
  3. 服务追踪:

    • 使用分布式追踪系统如Zipkin或Jaeger来追踪跨服务的请求,以便于理解请求流和诊断潜在问题。
  4. 日志聚合:

    • 使用如ELK栈(Elasticsearch、Logstash、Kibana)或Fluentd来收集、存储和分析日志。
  5. 性能监控:

    • 监控服务的性能指标,例如响应时间、吞吐量和错误率。
  6. 自定义度量:

    • 收集和监控业务关键性能指标(KPIs),确保微服务符合业务目标。
  7. 报警和通知:

    • 设置阈值,并在指标超出正常范围时触发警报通知相关人员。
  8. 依赖关系和服务地图:

    • 使用服务地图来展示服务之间的依赖关系,并监视这些关系的健康状态。

记录微服务日志

  1. 标准化日志格式:

    • 采用结构化日志格式(如JSON),使日志更容易被查询和分析。
  2. 包含上下文信息:

    • 在日志条目中包含足够的上下文信息,如服务名、时间戳、请求ID等。
  3. 日志级别:

    • 合理使用日志级别(如DEBUG、INFO、WARN、ERROR),以便于过滤和查找信息。
  4. 分布式追踪:

    • 在日志中包含跨服务调用的追踪ID,以便于关联分散于不同服务的日志。
  5. 日志记录策略:

    • 制定日志保留和旋转策略,以避免存储容量溢出。
  6. 安全和合规性:

    • 确保日志记录遵守数据保护和隐私法规,对敏感数据进行脱敏。
  7. 异常捕获:

    • 实现异常捕获机制,确保所有未处理的异常都被记录下来。
  8. 资源日志:

    • 监控和记录微服务所使用的底层资源,例如CPU、内存和网络。

通过这些策略,可以确保微服务能够被有效地监控和记录。监控可以提供实时的系统状态信息,而日志是事后诊断问题不可或缺的资源。这两者共同为微服务的稳定运行和问题解决提供支持。在现代的DevOps文化中,监控和记录也是持续改进和优化系统的基石。

10、微服务如何部署?

微服务的部署是一个复杂过程,需要考虑的因素包括服务的可发现性、网络配置、数据持久性、服务间通信、负载均衡、自动化部署、监控和日志记录等。以下是微服务部署的典型步骤和策略:

容器化

将微服务打包成容器,使用Docker等容器技术。容器化有助于确保在不同环境中应用程序的一致性。

持续集成和持续部署(CI/CD)

使用Jenkins、GitLab CI、CircleCI、GitHub Actions等工具自动化编译、测试和部署微服务。

服务编排

使用Kubernetes、Docker Swarm、Mesos或其他编排工具来管理服务的生命周期,包括部署、扩展和健康检查。

配置管理

使用Consul、Etcd或Spring Cloud Config等工具来集中管理和分发配置信息。

服务网格

采用Istio、Linkerd等服务网格技术来管理微服务间的通信,提供负载均衡、服务发现、失败恢复、追踪和度量。

服务发现

使用DNS或服务发现工具(如Eureka、Consul、Zookeeper)使服务能够找到彼此。

负载均衡

使用Nginx、HAProxy、Traefik等负载均衡器来分发客户端请求到后端服务。

自动扩展

配置自动扩展以便服务可以根据负载变化自动增减实例。

数据库和存储

每个服务可以拥有独立的数据库实例或共享访问控制良好的数据库。还需要考虑数据迁移和数据一致性。

环境隔离

在开发、测试和生产环境之间建立明确的隔离,以阻止代码和配置的意外泄漏。

安全性

确保在部署过程中实施适当的安全措施,比如使用HTTPS、配置网络安全策略等。

日志和监控

集成日志聚合和监控系统,以便跟踪服务的健康和性能。

回滚策略

准备好回滚机制,以便在部署新版本时出现问题可以快速恢复。

在现代云环境中,可以使用各种PaaS(平台即服务)提供商(如AWS、Azure、Google Cloud Platform)提供的服务和工具来简化部署过程。这些服务提供了上面提到的许多功能,从而使得微服务的部署更加容易和可靠。

11、API网关的作用

API网关是微服务架构中的一个关键组件,它处于客户端和服务端之间,起着流量管理和请求处理的作用。API网关的主要职责包括:

请求路由

API网关将接收到的外部请求路由到后端的正确微服务。对于客户端来说,API网关提供了一个统一的接口(endpoint),简化了与微服务后端的通信。

负载均衡

API网关通常负责对进入的请求进行负载均衡,确保请求被均匀地分配到后端服务的实例上,从而优化资源使用和响应时间。

授权与认证

API网关可以对进入的请求进行认证和授权,确保只有合法的请求能够访问后端服务。这有助于提升系统的安全性,并减轻后端服务的安全负担。

请求过滤与拦截

在请求到达后端服务之前,API网关可以对其进行审查,执行各种筛选规则,比如验证请求参数、限制IP地址等。

限流与熔断

API网关可以实现限流(rate limiting)和熔断(circuit breaking)策略,防止过多的请求冲垮后端服务,并在服务不可用时提供优雅的降级响应。

协议转换

API网关可以在不同的通信协议之间进行转换,例如,将外部的HTTP/HTTPS请求转换为内部使用的更高效的协议。

数据聚合

API网关可以从多个微服务聚合数据,然后将聚合后的数据作为一个统一的响应返回给客户端。这减少了客户端需要进行多次请求以获取不同服务数据的情况。

缓存

可以在API网关层面实现响应缓存,提高数据响应速度,降低后端服务的负载。

API版本管理

API网关能够管理不同版本的API,使得不同版本可以平稳过渡,提供向后兼容支持。

监控和日志记录

API网关可以记录和监控进出的流量,以及各种指标,如请求延迟、服务响应时间等,有助于性能分析和故障排查。

综合来说,API网关是微服务架构中的重要组成部分,它提供了一种机制来处理微服务间的交互,同时提供安全保护、流量控制以及监控功能。通过这些功能,API网关帮助微服务架构更高效、安全、稳定地运行。

12、什么是容错机制?

容错机制是指系统在面对部分组件失败或出现错误时,仍能继续正常运行的能力。在软件架构和系统设计中,这通常意味着采取预防措施和应对策略来处理潜在的错误情况,从而保证服务的持续性和可靠性。容错机制的目的是最小化错误对用户体验和系统整体功能的影响。

以下是一些常见的容错机制和策略:

冗余

在系统中引入冗余,意味着提供备份组件如服务器、数据库或网络路径。这样,当主要组件失败时,备用组件可以接管工作。

异常捕获和处理

编写代码时,对潜在故障点进行异常捕获,并实现相应的错误处理流程,确保程序在遇到错误时不会立即崩溃。

超时和重试逻辑

设置超时限制,并在操作未在预期时间内完成时进行重试。这对于处理网络请求和远程服务调用尤其重要。

熔断器模式

实现熔断器模式,可以在检测到一定阈值的失败时暂时中断服务调用,并在一段时间后重试,以避免连锁故障。

限流和降级

通过限制系统的入口流量,确保系统不会因为过载而崩溃。在系统资源不足时,优雅地降级服务,比如关闭非核心功能,以保证核心业务的运行。

分布式系统设计

在微服务和分布式系统设计中,容错是一个核心考虑因素。应用如分布式一致性协议(如Raft或Paxos)来确保系统的弹性。

备份和恢复

定期备份数据和系统状态,以便在发生灾难性故障时可以进行数据恢复。

数据一致性策略

设计数据一致性策略,如最终一致性模型,以在分布式环境中处理数据同步问题。

自动故障转移

实现高可用性集群,自动检测故障并将工作负载切换到健康的节点上。

监控和告警

部署监控系统以实时监控应用和基础架构的健康状况,并在检测到异常时发送告警。

容错机制是确保系统高可用性和可靠性的关键组成部分,特别是对于关键任务系统来说尤其重要。通过将容错设计作为系统开发的一部分,可以显著提高系统面对错误和失败时的韧性。

如何在微服务架构中实现和管理容错

在微服务架构中实现和管理容错通常涉及多个层面,包括应用程序设计、数据管理、网络通信和基础设施配置等。以下是在微服务架构中实现容错的一些关键策略:

1. 微服务设计原则

  • 隔离性: 确保服务之间的失败是隔离的,这样一个服务的问题不会影响到其他服务。
  • 无状态设计: 尽可能使服务无状态,这样可以简化水平扩展和负载均衡。
  • 服务降级: 当系统压力过大时,暂时关闭或降低一些服务功能以保证核心服务可用。

2. 负载均衡

  • 使用负载均衡器分散请求到多个服务实例,从而避免单点故障。

3. 服务发现

  • 实现服务注册和发现机制(如使用Consul、Eureka等),以动态管理服务实例。

4. 熔断和失败重试

  • 使用熔断器模式(如Netflix的Hystrix或Resilience4j)来防止级联故障。
  • 在服务调用中实现重试逻辑,但要设置重试次数和指数退避策略以避免过载。

5. 限流

  • 实施限流措施(如使用令牌桶或漏桶算法)以防止服务被过多的请求压垮。

6. 超时控制

  • 为远程调用设置合理的超时时间,确保系统可以及时响应服务延迟或不可用。

7. 服务监控和日志记录

  • 集成监控工具(如Prometheus、Grafana)来跟踪服务的健康和性能。
  • 实现集中式日志管理(如使用ELK栈)来分析问题和异常。

8. 持续交付和部署

  • 实施持续集成/持续部署(CI/CD)流程,以自动化服务的测试、部署和恢复。

9. 数据库和存储容错

  • 分布式数据库和持久化存储使用如主从复制、分片和数据备份等策略来确保数据的高可用和一致性。

10. 灾难恢复计划

  • 创建并测试灾难恢复计划,以快速恢复服务和数据。

11. 依赖管理

  • 分析和管理服务间的依赖关系,避免过度耦合。

12. 环境和配置管理

  • 使用环境管理工具(如Docker、Kubernetes)来维护服务配置和环境隔离。

13. 自动故障转移

  • 设置高可用集群和自动故障转移机制确保服务连续性。

14. 弹性测试

  • 定期进行弹性测试(如混沌工程)来发现和修正潜在的容错问题。

通过实施以上策略,可以建立一个韧性较强的微服务架构,即使在部分服务或组件失败的情况下,系统总体仍然能够保持运行和服务用户。这些策略有助于准备和应对不可预见的故障,降低它们对业务运营的影响。

13、如何处理跨服务的数据一致性?

处理跨服务的数据一致性是微服务架构中的一个重要挑战,因为服务通常需要独立地扩展、部署和管理。为了保持数据的一致性,可以采取以下策略:

1. 分布式事务

  • 两阶段提交(2PC): 一个经典的分布式事务协议,它分为准备和提交两个阶段,确保所有参与者都同意提交事务。
  • 三阶段提交(3PC): 一个在两阶段提交基础上增加了一个预提交阶段的改进协议,以减少阻塞和提高容错性。

2. 最终一致性

  • 异步通信: 通过消息队列(如RabbitMQ或Kafka)可以异步地传输数据变更,这有助于解耦服务并降低直接通信的需求。
  • 事件驱动架构: 使用事件来通知其他服务状态的变更,这些服务可以监听这些事件并相应地更新自己的数据状态。

3. 基于补偿事务的SAGA模式

  • SAGA: 分解传统的ACID事务为一系列本地事务,每个服务执行完自己的事务后发布事件,其他服务根据事件来执行下一个事务,这样通过一系列的本地事务来维护全局的数据一致性。

4. 使用数据一致性框架

  • 使用已经存在的工具和框架,如Apache Flink或Debezium,可以帮助捕获数据变动并将其同步到其他系统和服务。

5. 数据库技术

  • 分布式数据库: 选择支持多副本和分区容错的数据库系统,这些数据库可以在保持一致性的同时支持跨服务的数据复制。
  • 数据同步: 使用数据库层面的同步机制(如MySQL的复制功能)来同步不同服务之间的数据。

6. 依赖服务的幂等性

  • 确保服务对外提供的操作是幂等的,即多次执行同一操作,结果保持不变,这有助于安全地重试操作而不会破坏数据一致性。

7. 业务流程设计

  • 细化业务流程设计,理解各服务间的数据依赖性,以减少强一致性需求,转向可以接受一定时间窗口内的数据不一致。

8. 监控和告警

  • 监控数据流和服务状态,一旦检测到一致性问题,可以及时地发出告警并进行手动或自动修复。

9. 领域驱动设计(DDD)

  • 将系统分解成不同的业务领域,每个领域负责其数据的一致性,减少服务间的直接数据依赖。

10. 模式选择

  • 根据业务需求选择适当的一致性模式(强一致性、弱一致性、最终一致性等)。

11. 版本控制

  • 对于跨服务的数据变更,使用版本控制来处理并发更新的问题,确保数据更新的顺序性和一致性。

在选择以上策略时,重要的是理解不同业务场景对一致性的需求,并评估其在系统复杂性、性能和可用性方面的权衡。没有一种方法可以适合所有场景,因此通常需要结合使用多种策略来达到期望的一致性水平。

14、什么是领域驱动设计(DDD)?

领域驱动设计(Domain-Driven Design,简称DDD)是一套用于软件开发的概念和方法,它强调基于业务领域知识来进行软件设计,并使软件结构与业务模型保持一致。DDD由Eric Evans在其2004年出版的同名著作《Domain-Driven Design: Tackling Complexity in the Heart of Software》中提出,旨在解决复杂软件项目的设计问题。

领域驱动设计的核心概念和组成部分包括:

1. 领域

指的是软件项目所要解决问题的业务领域,包括业务领域的业务规则、逻辑、功能等。

2. 模型

在DDD中,模型是对领域知识的精确和凝练的表达,它不仅是数据模型,还包括业务规则、用例和业务逻辑。

3. 上下文

指明模型适用的边界,上下文间的映射关系称为上下文映射(Context Mapping),它有助于模块间的相互作用。

4. 领域服务

领域中的一些行为可能不属于任何一个实体或值对象,这时可以通过领域服务来实现这些行为。

5. 实体(Entities)

具有唯一身份标识的对象,即使它的属性发生变化,这个实体也依旧保持其唯一性。

6. 值对象(Value Objects)

没有唯一身份,仅由其属性所定义的对象。它们往往是不可变的。

7. 聚合(Aggregates)

一组具有统一生命周期的相关对象的集合,包括一个聚合根(Aggregate Root)和若干实体和值对象。

8. 聚合根(Aggregate Roots)

每个聚合有一个根实体,称为聚合根,它是聚合的入口,所有外部交互都通过聚合根进行。

9. 工厂(Factories)

用于封装创建领域对象的复杂性,确保创建出的对象是有效的。

10. 仓储(Repositories)

提供查找和持久化聚合根的方法,使得领域层的代码不需要关心数据持久化的细节。

11. 应用服务(Application Services)

作为领域模型和外界(比如用户界面、测试客户端等)的通信枢纽,负责协调领域对象完成业务用例。

DDD的目标是通过与领域专家的紧密合作,创建一个反映业务意图的丰富的领域模型,并以此为基础来驱动软件项目的设计。通过这种方式,DDD有助于创建既能满足用户需求又具有良好架构的软件系统。

什么是测试驱动开发(TDD)?

TDD是Test-Driven Development(测试驱动开发)的缩写,是一种软件开发过程,它依赖于对软件组件的短迭代和自动化测试用例的编写。这种方法强调在编写实际功能代码之前先编写测试代码,从而指导功能代码的编写。TDD的目标是通过这种方式来提高代码质量并促进敏捷和迭代开发。

TDD通常包括以下步骤:

1. 编写测试

在编写功能代码之前,首先编写一个失败的自动化测试用例,用来定义或改进一个新功能的需求。这个测试应该简单明了,直接反映需求的相关部分。

2. 运行测试

运行所有测试用例,确保新增的测试失败。这一步验证了测试确实是针对新功能的,因为在该功能不存在的情况下,测试是不能通过的。

3. 编写代码

编写最少量的代码来通过测试。这里的重点是速度和效率,而不是代码的完美。代码在此阶段可以不完美,因为它稍后还会被重构。

4. 再次运行测试

运行测试用例以确保新增的测试能够通过。这一步验证了新编写的代码满足了测试的需求,并且没有破坏现有的功能。

5. 重构代码

在确认新功能正确无误之后,可以对代码进行重构,以改善代码的结构和可读性。重构时也要确保所有的测试用例仍然能够通过。

6. 重复

重复以上步骤,为下一个功能编写新的测试,然后再次经过编写代码、测试和重构的循环。

TDD的好处包括:

  • 改进代码质量:由于TDD重视测试,因此可以在软件开发过程中尽早发现问题。
  • 简化调试:当测试失败时,只需要查看最近的代码更改即可,因为测试是逐步建立的。
  • 促进设计:为了使代码可测试,通常会导致更模块化、更灵活的设计。
  • 提供文档:测试本身就是一种文档形式,说明了代码应该如何工作。
  • 提升开发速度:虽然开始时会慢一些,但长期看来,TDD可以减少调试和修复错误的时间。

TDD是一种编程理念,它强调测试不仅仅是验证软件,而且是驱动设计的一部分,是一种从测试设计出代码的开发实践。

15、微服务的版本管理如何处理?

微服务的版本管理是在分布式系统中保持服务协调一致的一个挑战。版本管理确保在服务升级和维护过程中,整个系统能够稳定运行。以下是一些关于微服务版本管理的常用策略:

1. 语义化版本控制(Semantic Versioning)

这是一种常见的版本命名约定,格式通常是 MAJOR.MINOR.PATCH,例如 2.1.3。每个部分的含义如下:

  • MAJOR:当你做了不兼容的 API 修改,
  • MINOR:当你添加了向下兼容的功能时,
  • PATCH:当你做了向下兼容的问题修正时。

2. 持续集成/持续部署(CI/CD)

利用CI/CD管道自动化服务的构建、测试和部署,可以确保新版本的服务在部署到生产环境之前是稳定的。

3. 服务契约

定义服务间的接口契约,并确保在版本升级时不违反这些契约,从而保证服务间的兼容性。可以使用工具进行契约测试。

4. 服务发现与路由

使用服务发现和智能路由技术(如Netflix的Eureka和Zuul)来管理服务的版本。客户端请求可以被路由到指定版本的服务实例。

5. 平行运行多个版本

在过渡期间,可能需要同时运行多个版本的服务,直到旧版本的服务可以安全地下线。

6. 向后兼容性

在升级服务时,确保新版本的服务向下兼容。这通常需要额外的工作来支持旧版API。

7. 版本化API

为服务的API定义明确的版本,例如 v1, v2 等。这使得客户端可以选择他们需要的API版本。

8. API网关

使用API网关来提供一个统一的接入点,并管理不同版本的服务。API网关也可以处理请求的路由、负载均衡等。

9. 弃用策略

定义并明确沟通弃用旧版本服务的策略,包括弃用计划和时间表,以确保客户端有足够的时间迁移到新版本。

10. 逐步发布

利用蓝绿部署、金丝雀发布等策略逐步推出新版本,以便监控新版本对现有系统的影响并进行必要的调整。

11. 数据库版本管理

数据库的变更也需要管理。可以使用数据库迁移工具,如Liquibase或Flyway,来管理数据库模式的变更。

12. 配置管理

使用配置管理工具,如Spring Cloud Config,来集中管理服务配置,这样不同的服务版本可以共享或有选择地使用配置。

13. 日志和监控

确保所有版本的服务均具备完善的日志和监控,以便于发现问题并快速定位。

14. 文档管理

更新服务的文档,确保用户和开发人员了解不同版本的变更。

通过上述策略的结合使用,可以有效地管理微服务环境中的版本,同时减少服务更新对系统稳定性和用户体验的负面影响。

如何在不中断服务的情况下更新服务?

在不中断服务的情况下更新服务是微服务架构中的一个常见需求。为了实现这一点,通常采取以下策略来确保零停机部署或最小化停机时间:

1. 蓝绿部署(Blue-Green Deployment)

这种策略涉及两个生产环境(蓝色和绿色)。在蓝色环境中运行当前版本的服务,而绿色环境则用于准备和部署新版本的服务。一旦绿色环境准备就绪并且通过了所有测试,就可以通过切换负载均衡器的配置将流量从蓝色环境切换到绿色环境,实现无缝的服务更新。

2. 金丝雀发布(Canary Releases)

金丝雀发布是逐渐将新版本服务推向生产环境的一种方式。最初,只有少量的用户(比如1%的流量)会被路由到新版本,以便监控新版本的表现。如果一切正常,逐渐增加流量,最终完全用新版本替代旧版本。

3. 滚动更新(Rolling Update)

在此策略中,更新过程将分批逐个或逐组替换旧服务实例。在一个服务实例更新并成功运行后,下一个服务实例随即更新,直至所有实例更新完毕。这通过管理服务实例的顺序来确保服务的连续可用性。

4. 版本控制

服务更新时,新旧版本可能需要并行运行一段时间。通过API版本控制,可以确保客户端在此过程中不受影响。客户端可以指定他们希望使用的API版本,从而可以同时使用新旧版本的服务。

5. 功能标记(Feature Flags)

使用功能标记可以控制新功能的启用或禁用,无需修改代码即可在生产环境中测试新功能。这使得可以随时启用或回滚新功能,而不中断服务。

6. 微服务代理或API网关

通过使用API网关或微服务代理来管理请求路由,可以在服务更新时动态地路由请求到不同版本的服务实例。

7. 自动化测试和监控

在服务更新期间,自动化测试和实时监控对于确保服务稳定性至关重要。通过自动化测试可以确保新服务版本的质量,而监控可以快速发现并解决问题。

8. 数据库的向前兼容性

确保数据库的变更是向前兼容的,这样新旧服务版本都可以与相同的数据库版本正常交互。

9. 配置管理

更新配置管理系统来支持新版本的服务,同时保留旧版本服务所需的配置。

10. 处理状态和会话数据

确保在更新过程中,关键的状态和会话数据得到妥善管理,以防数据丢失或服务中断。

11. 服务降级和熔断机制

在更新过程中,如果新版本的服务出现问题,应该有机制能够自动降级到旧版本或者通过熔断机制防止系统级的错误。

通过以上方法,可以在不中断服务的情况下实现服务的平滑更新。这些策略有助于提高系统的可用性和可靠性,同时减少对终端用户的影响。

16、什么是断路器模式?

断路器模式(Circuit Breaker pattern)是一种软件设计模式,常用于微服务架构中以提高系统的弹性。该模式受到了电路中断路器的启发,旨在防止系统中的一个服务(或调用)失败,导致进一步的系统级失败。

在微服务架构中,服务之间通过网络进行通信,如果一个服务变得不稳定(例如,由于过载或网络问题),在不采取任何措施的情况下,其他服务继续向其发送请求将可能使问题进一步恶化,导致资源耗尽,甚至可能造成雪崩效应,影响整个系统的稳定性。

断路器模式通过以下方式工作来预防这些问题:

1. 监控

断路器监控由服务客户端发起的对特定服务的调用。如果调用中的错误数量超过预先设定的阈值,断路器会被触发。

2. 打开状态(Open State)

一旦错误率超过阈值,断路器就会“打开”。在这种状态下,后续的请求会被断路器拦下,不再调用远程服务。相反,客户端可能会收到一个预定义的回退响应,或者请求可能被抛出异常。这有助于防止不稳定服务的进一步恶化。

3. 休眠时间(Sleep Window)

断路器打开之后,会进入一个休眠时间窗口。在这个时间窗口内,断路器会阻止请求的流向不稳定服务。

4. 半开状态(Half-Open State)

休眠时间过后,断路器进入半开状态。在这个状态中,允许有限数量的测试请求通过断路器到达下游服务。如果这些请求成功,表明下游服务可能已经恢复,断路器将会关闭并恢复正常操作。如果这些测试请求失败,断路器将再次打开,并进入另一个休眠周期。

5. 关闭状态(Closed State)

当下游服务恢复正常时,断路器关闭,允许所有请求正常通过。但断路器仍然会继续监控请求,并在发现失败达到阈值时再次开启。

使用断路器模式的好处包括:

  • 防止故障扩散:快速失败机制可以阻止一个服务的问题传播到其他服务。
  • 快速恢复:当下游服务恢复时,可以快速恢复正常通信。
  • 资源节约:避免向已知故障的服务发送请求,从而节省系统资源。
  • 更好的用户体验:通过提供回退机制,即使在某个服务失效时,用户也可以获得一些功能。

断路器模式通常与其他弹性模式一起使用,如超时、重试策略和回退机制,以构建更为健壮和可靠的分布式系统。在实践中,可以使用现成的库,如Netflix的Hystrix(虽然已进入维护模式),Resilience4j,或者在Spring Cloud中的断路器支持来实现断路器模式。

断路器模式如何在微服务架构中提供稳定性

在微服务架构中,断路器模式通过以下方式提供稳定性:

1. 防止故障扩散

在微服务架构中,服务之间常常存在依赖关系。一个服务的故障可能会导致依赖它的其他服务也出现问题。断路器通过阻止对故障服务的进一步调用来阻止这种连锁反应,从而限制故障的影响范围。

2. 保护不稳定服务

当服务不稳定或过载时,继续向其发送请求会进一步恶化情况。断路器通过“打开”来停止请求到达不稳定服务,给予服务恢复的时间,降低了服务崩溃的风险。

3. 促进恢复

断路器在开启后,会进入一个预设的“休眠时间窗口”,在这个时间后,它将允许少量的流量通过,这种半开状态(Half-Open State)允许系统逐步尝试恢复正常操作,而无需等待外部干预。

4. 回退机制

当断路器打开时,可以提供一个备用的回退答案或行为给客户端,这比简单地抛出异常或超时要好。这些回退可以是缓存的数据、默认值或者错误信息,它们提供了用户体验的连续性。

5. 提高系统响应性

在高负载或故障情况下,请求可能会在系统内部传递并排队,导致延迟增加。断路器通过短路这些请求,避免了额外的延迟,保持了系统的响应性。

6. 强制超时

断路器模式通常与超时策略结合使用,强制长时间运行的操作失败。这防止了系统资源被慢操作长时间占用。

7. 易于管理和维护

断路器模式可以通过集中式的管理界面进行监控和配置,使得运维团队可以更好地理解系统的状态并做出快速反应。

8. 自我修复能力

在某些实现中,断路器可以配置自动恢复策略,当服务稳定性得到保证后,自动将断路器置于关闭状态,恢复正常流量。

9. 提高系统的可预测性

通过设置明确的操作模式和回退策略,系统在遇到问题时的行为变得更加可预测,允许系统设计者更好地理解系统在各种条件下的表现。

断路器模式是一种在分布式系统中实现稳定性的重要机制,它有助于保护系统免受单点故障的影响,并确保整个微服务架构能够更加可靠地运行。

断路器有哪些

在详细介绍之前,我们需要区分两类“断路器”:一类是软件工程中的设计模式,即断路器模式,用于提高分布式系统的弹性和稳定性;另一类是电气工程中的物理装置,用于在电路故障时切断电流以防止进一步的损害。这里我们重点介绍软件工程中不同库的断路器模式及其用法。

1. Hystrix(Java)

用法:
Hystrix提供了一个HystrixCommandHystrixObservableCommand的类,您可以继承这些类并覆盖它们的run方法来执行受保护的操作。例如:

public class CommandHelloWorld extends HystrixCommand<String> {

    private final String name;

    public CommandHelloWorld(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.name = name;
    }

    @Override
    protected String run() {
        // 实际的服务调用
        return "Hello " + name + "!";
    }

    @Override
    protected String getFallback() {
        return "Fallback Hello " + name;
    }
}

// 使用
String s = new CommandHelloWorld("Bob").execute();

Hystrix还提供了一个监控仪表板用于观察断路器的状态和度量指标。

2. Resilience4j(Java)

用法:
Resilience4j是一个轻量级的容错库,它是通过装饰器模式来使用的。您可以创建断路器的实例,并通过装饰您的函数调用来使用它:

CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)
    .waitDurationInOpenState(Duration.ofMillis(1000))
    .ringBufferSizeInHalfOpenState(2)
    .ringBufferSizeInClosedState(2)
    .build();

CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);

CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("my");

Supplier<String> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, () -> "Hello");

Try.ofSupplier(decoratedSupplier)
    .onFailure(throwable -> System.out.println("We might be in fallback mode!"));

3. Polly(.NET)

用法:
Polly是一个.NET弹性和瞬态故障处理库,它支持许多弹性策略包括断路器。下面是Polly使用断路器的一个例子:

CircuitBreakerPolicy breaker = Policy
    .Handle<Exception>()
    .CircuitBreaker(
        2, // 在开启断路器之前允许几次连续异常
        TimeSpan.FromMinutes(1) // 断路器打开的时间
    );

try
{
    breaker.Execute(() => {
        // 受保护的代码
    });
}
catch (BrokenCircuitException)
{
    // 断路器打开的操作
}

4. Sentinel(Java)

用法:
Sentinel主要用于流量控制,同时也支持熔断机制。使用Sentinel进行熔断保护的例子:

List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule("some_resource")
    .setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
    .setCount(0.5)
    .setTimeWindow(60);
rules.add(rule);
DegradeRuleManager.loadRules(rules);

try (Entry entry = SphU.entry("some_resource")) {
    // 受保护的业务逻辑
} catch (BlockException ex) {
    // 资源被熔断时进入的逻辑
}

5. Akka(Scala/Java)

用法:
在Akka框架中,断路器通常用于Actor模型中,以管理Actor之间的消息传递。一个Akka断路器的例子:

import akka.pattern.CircuitBreaker
import scala.concurrent.duration._

val breaker = new CircuitBreaker(system.scheduler,
  maxFailures = 5,
  callTimeout = 10.seconds,
  resetTimeout = 1.minute)
  .onOpen(notifyMeOnOpen())

breaker.withCircuitBreaker(Future {
  // 受保护的代码
})

6. Spring Cloud Circuit Breaker(Java)

用法:
Spring Cloud Circuit Breaker为不同的断路器实现提供了一个抽象层。这里是一个使用Resilience4j的例子:

@Service
public class BusinessService {
    private final CircuitBreaker circuitBreaker;

    public BusinessService(CircuitBreakerFactory circuitBreakerFactory) {
        this.circuitBreaker = circuitBreakerFactory.create("my");
    }

    public String someMethod() {
        return circuitBreaker.run(() -> {
            // 受保护的服务调用
            return "success";
        }, throwable -> "fallback");
    }
}

这些是一些流行的断路器库及其在不同编程语言中的基本用法。值得注意的是,每个库都有许多配置选项来调整断路器的行为,以适应具体的应用场景。使用断路器时,通常需要根据服务的特性来配置故障阈值、调用延迟、断路器打开的持续时间等参数,并监控其对系统行为的影响。

17、微服务间的通信延迟如何解决?

微服务架构中的服务间通信延迟是一个常见的问题,它可能由网络延迟、服务负载、资源竞争等多种因素造成。下面是一些常用的策略来解决或减少通信延迟:

1. 异步通信

改用异步消息传递,例如使用消息队列(如RabbitMQ、Kafka等)或事件总线,可以减少对即时响应的依赖,并且可以通过后台处理来提高整体性能。

2. 服务实例扩展

水平扩展(增加服务实例)可以提高服务的处理能力,减少单个实例的负载,从而降低响应时间。

3. 优化网络

使用快速、低延迟的网络基础设施,包括硬件(如更快的路由器和交换机)和软件(如优化的网络协议栈)。

4. 缓存策略

对于不经常变化的数据,可以在服务消费者一侧或服务提供者一侧实现缓存,这样可以减少重复的数据检索请求。

5. 数据本地化

将数据存储在与服务实例位置相接近的位置,这样可以减少数据传输时间。

6. 使用API网关

一个API网关可以提供聚合服务,这样一个外部请求就可以通过一个单独的调用来聚合多个服务的响应,减少了客户端与各个微服务间的通信次数。

7. 服务拆分

对于响应时间要求极高的功能,可以进一步拆分服务,使其足够小,并且仅包含必要的逻辑,以此减少计算和通信时间。

8. Connection Pooling

使用连接池可以减少频繁建立和关闭连接的开销,尤其是当微服务之间通过HTTP调用时。

9. 负载均衡

合理分配请求到不同的服务实例,避免个别服务点的过载,可以使用软件负载均衡器如Nginx,或者云服务提供的负载均衡器如AWS ELB。

10. 超时和重试策略

设置合理的超时和重试策略可以减少因等待响应而造成的时间浪费,尤其是在服务依赖链较长的情况下。

11. 协议优化

使用更快的通信协议,例如gRPC而不是HTTP REST,因为gRPC使用了HTTP/2特性,如头部压缩和多路复用,以及更有效的二进制消息格式。

12. 性能监控和分析

实时监控服务性能,并分析瓶颈的原因是识别和解决通信延迟问题的关键。可以使用APM工具(如New Relic, Datadog等)来执行此任务。

13. 服务合并

将频繁进行交互的微服务合并成一个服务,以减少网络通信。

14. 避免复杂的服务链

服务间的过度依赖和复杂的调用链会增加延迟,应当尽量避免。

应用以上这些方法时,重要的是要平衡延迟减少和资源使用、成本和系统复杂度之间的关系。通常,最好是首先对系统进行性能分析,以确定延迟问题的根本原因,然后选择最适合您特定情况的解决方案。

18、微服务架构中的事务管理如何实现?

在微服务架构中,事务管理是一个复杂的问题。由于服务分布在不同的系统甚至不同的地理位置,传统的ACID(原子性、一致性、隔离性和持久性)事务模型很难直接应用。微服务架构通常依赖于BASE(基本可用、软状态、最终一致性)事务模型,其中最终一致性是关键特征。

以下是微服务事务管理的一些常见策略:

1. 分布式事务

  • 两阶段提交 (2PC): 两阶段提交是一种经典的分布式事务协议,它将事务的提交过程分为两个阶段:准备阶段和提交/回滚阶段。尽管它可以提供强一致性保证,但由于性能和可用性的挑战,它通常不适用于高度分布式的微服务环境。

  • 三阶段提交 (3PC): 这是对2PC的改进,增加了一个预提交阶段以减少阻塞和提高系统的容错性。但它也面临着性能和复杂性的挑战。

2. Saga模式

Saga是一种解决分布式系统事务的方法,它将长期事务拆分为一系列本地事务,每个微服务都执行它的本地事务并发布事件或消息以触发下一个微服务的本地事务。

  • Choreography-based Sagas: 在此方法中,每个服务都知道下一步要调用的服务(或要发送的事件)。它通过监听前一个服务发布的事件来执行其事务。

  • Orchestration-based Sagas: 在这种方法中,一个中心化的服务(称为Saga协调器或导向器)负责告诉参与的服务何时执行哪个本地事务。

3. 异步消息传递和最终一致性

通过使用消息队列(如RabbitMQ、Apache Kafka等),服务可以异步地进行通信,从而降低了事务间耦合度。这种情况下,系统设计为接受最终一致性,而不是立即一致性。

4. 补偿事务/补偿逻辑

对于Saga模式中的每个本地事务,你需要实现补偿逻辑(即回滚操作)。如果后续步骤失败,系统将执行补偿事务以撤销之前的操作。

5. 手动干预

在某些情况下,自动补偿可能不可行或不足以处理所有的错误情况,此时需要人工干预来解决事务问题。

6. 使用分布式事务框架

现在有一些框架和平台,如Seata、Atomikos和Narayana,它们提供了分布式事务的解决方案,可以帮助开发者更容易地管理跨微服务的事务。

7. 超时和重试机制

在某些情况下,特别是在网络不稳定的情况下,设置超时和重试机制可以帮助补偿因暂时性问题而失败的事务。

8. 事件驱动架构

通过事件驱动架构,可以通过发布和订阅事件来确保数据的一致性。这要求系统设计能够处理事件重复、失序和丢失的情况。

在实现这些策略时,关键是要理解业务需求和事务的特性。每种策略都有其优势和局限性。在选择时,应权衡一致性、性能、复杂性和业务的容错需求。通常,提高系统的容错能力和设计健壮的恢复策略是微服务事务管理的关键。

19、如何处理服务依赖和服务间的耦合?

服务依赖和服务间耦合是微服务架构中常见的问题。理想情况下,每个微服务都是独立的,有自己的数据库和业务逻辑,可以独立部署和扩展。然而,在实际应用中,服务之间往往存在一定程度的依赖和耦合。以下是一些应对策略:

1. 定义明确的服务接口

确保服务之间的交互通过定义良好的API进行。服务不应该共享数据库或数据存储,而是应该通过API调用来交换数据。这有助于减少服务间的直接耦合。

2. 异步通信

使用消息队列、事件总线或其他异步通信机制(例如Kafka、RabbitMQ)可以降低服务间的耦合。服务不必在调用时立即响应,而是可以在处理能力允许的情况下处理消息。

3. 使用领域驱动设计 (DDD)

DDD鼓励将系统划分成不同的领域,每个领域内部维护自己的逻辑和数据,这有助于边界清晰的微服务设计,从而减少服务间的耦合。

4. 服务契约

服务间的交互应该基于稳定且向后兼容的契约。这意味着即使服务内部发生变化,只要对外提供的接口保持不变,其他服务就不会受到影响。

5. 服务发现

服务依赖可以通过服务发现机制来管理,使服务能够在运行时查找并与其他服务通信。这样可以在不硬编码服务位置的情况下灵活地处理依赖。

6. 服务网关

使用API网关可以将客户端和服务之间的交互进行解耦。客户端通过API网关发送请求,网关负责将请求路由到相应的服务。

7. 超时和重试策略

为服务间的调用实现超时和重试逻辑可以提高系统的弹性。这样,如果一个服务暂时不可用,调用它的服务可以重试,而不是立即失败。

8. 使用断路器模式

断路器模式可以防止服务间的级联失败。当特定服务出现问题时,断路器可以“跳闸”(开启状态),这样对该服务的进一步调用会快速失败而不是等待超时。

9. 负载均衡

负载均衡可以分散对单个服务实例的请求压力,有助于避免服务过载并提高可用性。

10. 分层架构

使用分层架构可以减少服务之间的直接依赖。例如,可以构建一个内部层,处理服务通用的逻辑和数据管理,并允许业务层服务专注于实现具体的业务逻辑。

11. 遵循最小知识原则

服务应该只了解它们直接依赖的服务,而不是整个系统的细节。

12. 自治性

每个服务应该尽可能自治,这意味着它拥有自己的数据源,并负责管理自己的数据一致性和完整性。

通过遵循这些策略,您可以减少服务间的耦合并更好地管理服务依赖,从而提高整个微服务架构的可维护性、可扩展性和弹性。

20、如何处理微服务的故障排除的?

故障排除是微服务架构中的一项关键活动,因为它涉及到定位并解决可能影响多个服务和分布式系统组件的问题。以下是处理微服务故障排除的一系列策略和步骤:

1. 监控和日志记录

  • 集中式日志管理:用像ELK Stack(Elasticsearch, Logstash, Kibana)或Splunk这样的工具来集中管理和分析日志。
  • 监控工具:使用Prometheus、Datadog、New Relic等工具来监控服务的性能指标。

2. 分布式跟踪

  • 实现如Zipkin、Jaeger这样的分布式跟踪系统来跟踪跨多个服务的请求。

3. 定义健康检查

  • 对每个服务实现健康检查端点,以便能够快速检测服务状态。

4. 故障排除步骤

  • 验证报告的问题:确认问题的存在,并尝试复现。
  • 检查服务状态:使用健康检查端点来确定服务是否运行正常。
  • 审查日志:查看相关服务的日志以寻找错误或异常信息。
  • 跟踪请求:使用分布式跟踪来了解请求在系统中的路径。
  • 性能指标:检查CPU、内存、网络I/O等指标来确定瓶颈或资源竞争。
  • 数据库状态:检查数据库连接、查询延迟、锁等情况。
  • 配置检查:确认所有的配置(环境变量、服务配置等)是否正确。

5. 自动化故障排除

  • 自动重启:容器编排工具(如Kubernetes)可以在服务失败时自动重启服务。
  • 自动扩展:根据负载自动增加或减少服务实例数量。

6. 通讯检查

  • 确认服务间的网络连接,检查防火墙、负载均衡器、服务发现机制等。

7. 缩小问题范围

  • 逐步排除正常运行的服务,直到找到故障点。

8. 使用断路器模式

  • 确定是否有断路器跳闸,这可能是由于下游服务的故障。

9. 重现问题

  • 在非生产环境中重现问题,以便能够自由地进行测试而不会影响生产。

10. 隔离和测试

  • 隔离可能的故障点,并在隔离的环境中进行测试。

11. 版本回滚

  • 如果最近有更新,考虑将服务回滚到上一个稳定的版本。

12. 求助社区和文档

  • 查阅官方文档、论坛和社区,了解是否已知的问题或者其他用户遇到过类似情况。

13. 修复和验证

  • 一旦找到问题源头,修复它,并在所有相关环境中进行验证。

14. 总结经验

  • 故障解决后,记录问题的原因、解决方法和学到的经验,以便以后参考并改进系统。

确保在处理过程中尽可能地自动化和记录,这将有助于未来更快地识别和解决问题。此外,良好的通信机制对于故障排除也很重要,确保所有团队成员都了解当前的问题和正在采取的行动。

21、如何进行微服务的性能测试?

微服务的性能测试是确保每个服务都能在规定的性能要求内运行的重要步骤。在微服务架构中进行性能测试可能涉及多个服务及其交互,下面是进行微服务性能测试的几个关键步骤:

1. 定义性能目标

  • 服务水平目标 (SLOs):定义清晰的性能指标,例如响应时间、吞吐量和可用性。
  • 服务水平指标 (SLIs):识别可以量化以上性能目标的关键指标。

2. 测试环境准备

  • 确保测试环境与生产环境尽可能相似,包括硬件、网络配置、数据库、缓存等。
  • 使用服务虚拟化或模拟依赖项,以便单独测试各个微服务。

3. 性能测试工具选择

  • 选择适合微服务架构的性能测试工具,如JMeter、Gatling、Locust等。

4. 测试场景设计

  • 设计测试场景,以覆盖正常的操作,以及压力测试和极限情况。
  • 考虑用户的不同行为模式和路径来模拟真实世界的请求。

5. 自动化和基准测试

  • 自动化测试脚本以支持持续集成/持续部署(CI/CD)流程。
  • 进行基准测试来确定系统在无负载情况下的性能。

6. 负载测试

  • 逐步增加负载,直到达到预定的性能指标或系统性能下降为止。

7. 压力测试

  • 继续增加负载,直到系统崩溃,以确定系统的破坏点。

8. 端到端测试

  • 执行端到端的性能测试来分析整个系统的表现。

9. 分析和监控

  • 实时监控系统指标(CPU、内存、网络I/O、数据库响应等)。
  • 分析测试结果,确定瓶颈和性能瓶颈。

10. 隔离和优化

  • 针对识别的性能问题进行隔离和优化。
  • 对特定服务或数据库进行优化,例如,通过增加缓存、数据库索引或调整查询逻辑。

11. 回归测试和验证

  • 在进行了优化之后,重复执行性能测试以验证改进效果。

12. 持续监控

  • 在生产环境中实施持续的性能监控,以便及时发现性能下降的问题。

13. 测试报告

  • 创建详细的性能测试报告,记录测试结果和改进措施。

14. 可观察性

  • 加强系统的可观察性,以便在真实环境中监控和理解微服务的行为。

在进行微服务性能测试时,需要注意以下几点:

  • 微服务通常独立部署和缩放,因此需要分别测试每个服务和整个系统。
  • 微服务可能会有复杂的服务间依赖,这在测试时需要特别关注。
  • 测试应该尽量模拟真实的使用情况,包括高峰时段和非高峰时段的负载模式。

性能测试不仅是一个技术挑战,也是一个持续的过程,需要随着系统的演进不断进行迭代和改善。

22、你会使用哪些方法和工具来测试微服务性能。

测试微服务性能需要采用综合的方法和多种工具,以确保各项性能指标达标。以下是一些常用的方法和工具:

方法:

  1. 负载测试:模拟预期的用户负载,观察系统如何在正常使用条件下运行。
  2. 压力测试:超出正常操作负载,找出系统的极限和瓶颈。
  3. 耐久性测试(也称为长时间运行测试):观察系统在持续负载下的表现,检查内存泄漏等问题。
  4. 并发测试:测试系统处理多个并发请求的能力。
  5. 容量测试:确定系统在当前架构下可以支持的用户数量和事务量。
  6. 灾难恢复测试:测试在某个或多个微服务失效时,系统恢复到正常运行状态所需的时间。

工具:

  1. JMeter:一个广泛使用的开源负载测试工具,适合进行各种性能测试。
  2. Gatling:高性能的基于Scala的负载测试工具,它提供详尽的报告。
  3. Locust:一个开源负载测试工具,使用Python编写,可以定义用户行为并在分布式系统中进行测试。
  4. ApacheBench (ab):一个简单的命令行工具,用于快速进行性能测试。
  5. Taurus:一个开源工具,它提供了一个抽象层,可以与JMeter、Gatling和其他工具结合使用。
  6. Vegeta:一个Go语言写的HTTP负载测试工具,适合于测试HTTP服务。
  7. Artillery:一个现代、强大的负载测试和集成测试工具,对于构建复杂的测试脚本很有帮助。
  8. K6:一个开源负载测试工具,它允许开发者使用JavaScript编写测试脚本,可集成到CI/CD管道中。

监控和跟踪工具:

  1. Prometheus:一个开源系统监控和警报工具包,适合收集和存储时序数据。
  2. Grafana:用于数据可视化,常与Prometheus结合使用。
  3. Zipkin:一个分布式跟踪系统,它帮助收集微服务中的定时数据,以便追踪系统的延迟问题。
  4. Jaeger:用于监控和故障排除微服务架构的分布式跟踪系统。
  5. Elastic Stack (ELK):Elasticsearch、Logstash和Kibana的组合,强大的日志监控和分析平台。

性能分析工具:

  1. Wireshark:网络协议分析器,对于分析和故障排除网络问题很有帮助。
  2. New Relic / Datadog:这些SaaS平台提供综合的监控解决方案,包括性能监控、应用性能管理(APM)等。
  3. Nginx Amplify:监视NGINX实例和微服务性能的工具。

在选择工具和方法时,要考虑到测试的特定需求、团队的技能水平以及工具的集成能力。通常,强大的监控和跟踪是进行有效性能测试的关键。此外,确保测试环境与生产环境尽可能接近也是获取有价值测试结果的重要条件。

23、你在微服务架构中实施的最佳实践

微服务架构设计和实施的最佳实践集中在提高系统的可维护性、可扩展性、弹性和安全性。以下是一些关键的最佳实践:

1. 服务划分与界定

  • 细粒度服务:基于业务功能界定服务的边界,遵循单一职责原则。
  • 领域驱动设计 (DDD):使用领域模型来指导服务的分解。

2. 独立性与封装

  • 服务自治:确保每个微服务是独立的,拥有自己的数据存储和依赖,能够独立部署。
  • API抽象:通过定义清晰的API来封装服务,隐藏其内部实现。

3. 配置管理

  • 外部配置:服务的配置应该与其代码库分离,并能够根据环境变化。
  • 配置中心:使用配置服务器或配置管理工具来集中管理配置。

4. 数据管理

  • 数据库分离:每个服务应拥有私有的数据库,避免数据库集中。
  • 数据一致性:使用事件驱动架构和最终一致性模式处理数据同步。

5. 通信机制

  • 异步通信:尽可能使用消息队列和事件总线实现服务间的异步通信。
  • API网关:使用API网关来统一入口点,提供认证、授权和流量控制。

6. 弹性设计

  • 断路器模式:防止服务故障的连锁反应。
  • 回退机制:在依赖的服务不可用时提供备选方案。
  • 超时机制:为网络请求设置合理的超时时间。

7. 可观察性

  • 日志聚合:集中管理服务日志,方便跟踪和问题排查。
  • 监控与告警:监控关键性能指标,并在问题发生时发送告警。
  • 分布式跟踪:实现对分布式请求的跟踪,以便分析和优化性能。

8. 测试与部署

  • 持续集成/持续部署 (CI/CD):自动化测试和部署流程,确保快速可靠的迭代。
  • 容器化:使用Docker等容器技术来实现服务的可移植性和一致性。
  • 编排工具:利用Kubernetes等工具来管理服务的部署和扩展。

9. 安全性

  • 服务间的认证和授权:确保服务之间的交互是安全的。
  • 敏感数据加密:对敏感数据进行加密处理,并安全管理密钥。

10. 设计用于故障的系统

  • 混沌工程:通过有意识地引入故障来测试系统的弹性。
  • 灾难恢复计划:准备并经常测试灾难恢复计划。

实施这些最佳实践时,需要不断地回顾和调整,因为技术和业务需求的变化可能会导致最初的假设和设计需要改进。此外,团队文化和技术栈的选择也会影响所采取的具体实践。最重要的是创建一个反馈环,以确保持续的改进和学习。

24、在使用微服务中需要注意什么

在使用微服务架构时,需要注意以下几个关键点:

服务粒度

  • 合理的服务大小:服务应该足够小,便于维护和独立部署,但也不能太小,否则可能会增加通信复杂性和部署难度。

数据管理

  • 数据一致性:微服务架构中的服务通常拥有自己的数据库,需要特别注意跨服务数据一致性的问题。
  • 数据隔离:确保服务之间的数据访问是安全的,并且每个微服务对自己的数据有完全的控制权。

网络通信

  • 网络延迟和可靠性:微服务间通信会引入额外的网络延迟,需要设计高效的通信协议和处理网络不可靠性的策略。

服务部署

  • 自动化部署:使用持续集成和持续部署(CI/CD)来自动化微服务的部署过程。

弹性与容错

  • 容错机制:实现断路器、重试、超时、限流等模式来增加系统的鲁棒性。
  • 服务监控和告警:实施全面的监控策略,以快速响应服务故障或性能下降。

安全性

  • 服务之间的安全通信:确保使用适当的认证和授权机制来保护服务之间的通信。
  • 安全的数据存储:对敏感数据进行加密,并妥善管理访问权限。

开发与运维协作

  • DevOps文化:鼓励开发和运维团队的紧密合作,以实现快速迭代和稳定运营。

服务发现与注册

  • 服务发现机制:服务需要能够找到彼此,使用服务注册表和服务发现机制可以简化这一过程。

API管理

  • 版本控制和文档:API的变更需要进行严格的版本控制,同时提供完善的文档。

技术栈多样性

  • 技术债务:虽然微服务允许使用不同的技术栈,但过度多样化可能会导致维护困难。

团队结构

  • 服务团队自治:每个服务的团队应该有能力独立管理服务的全生命周期,从设计到开发、部署和维护。

性能优化

  • 服务间调用优化:需要合理安排同步和异步调用,减少不必要的服务间交互。

在使用微服务架构时,理解这些挑战并采取相应的策略是至关重要的,以确保系统的整体健康、可维护性和可扩展性。此外,随着微服务应用的不断发展,持续评估和改进架构是一个必要的过程。

25、

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一些常见的Java微服务面试题及其答案: 1. 什么是微服务微服务是一种架构风格,它将单一应用程序拆分成一组小型服务。每个服务都运行在其自己的进程,使用轻量级通信机制(如HTTP API)进行通信。每个服务都专注于执行一项特定的业务功能,可以独立地扩展和部署。 2. 微服务的优点是什么? 微服务的优点包括: - 可扩展性:由于每个服务都是独立的,因此可以根据需要独立扩展。 - 可维护性:每个服务都专注于执行一项特定的业务功能,因此可以更容易地理解和维护。 - 独立部署:每个服务都可以独立地部署和升级,而不会影响整个应用程序。 - 可组合性:由于每个服务都使用轻量级通信机制进行通信,因此可以更容易地将它们组合在一起以构建复杂的应用程序。 - 技术多样性:每个服务都可以使用不同的技术堆栈,这使得团队可以选择最适合其需求的技术。 3. 什么是Spring Cloud? Spring Cloud是一组用于构建微服务的开源工具,它基于Spring Framework和Spring Boot构建。它提供了一组工具,用于实现服务注册和发现、负载均衡、断路器模式、配置管理等功能。 4. 什么是服务注册和发现? 服务注册和发现是一种机制,用于在微服务架构管理服务。当一个服务启动时,它将自己注册到注册。其他服务可以查询注册心以发现可用的服务,并使用它们提供的API进行通信。 5. 什么是负载均衡? 负载均衡是一种机制,用于将负载分配到多个服务器上。在微服务架构,负载均衡可以用于将请求分配到多个服务实例,以提高可用性和性能。 6. 什么是断路器模式? 断路器模式是一种机制,用于处理故障和延迟的服务。当服务不可用或响应时间过长时,断路器会打开,以避免向应用程序返回错误的响应。当服务恢复时,断路器会关闭,并将请求重新发送到服务。 7. 什么是配置管理? 配置管理是一种机制,用于管理应用程序的配置。在微服务架构,配置管理可以用于在不停止应用程序的情况下更新应用程序的配置。 Spring Cloud Config是一个用于实现配置管理的工具。 以上是一些常见的Java微服务面试题及其答案。当然,微服务是一个非常广泛的话题,还有很多其他的问题和细节需要考虑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辞暮尔尔-烟火年年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值