嗨,你好呀,我是猿java
什么是微服务?
微服务架构的核心理念是将单体应用程序拆分为多个小型服务,每个服务都是一个独立的进程,通常通过轻量级的通信机制(如HTTP/REST、消息队列等)进行交互。每个微服务都拥有自己的数据存储,可以选择最适合其功能的数据库类型。
微服务架构的模型可以抽象成下图:
微服务主要包含以下 5个特点:
1. 单一职责原则
微服务的设计理念强调每个服务模块应该聚焦于完成一项特定的任务或功能,遵循单一职责原则。这意味着每个微服务应该解决某一特定业务领域的问题,使得服务更易于开发、维护和理解。
2. 独立部署
微服务可以独立部署和更新,而无需影响整个系统。这样一来,可以更快地响应业务需求的变化,部署新的功能也更加便捷。
3. 去中心化管理和治理
在微服务架构中,基础设施和服务的开发由不同的团队负责,这样各个团队可以根据自身的技术栈独立决定如何实现服务,并采用适合的技术进行治理。去中心化的治理模型支持团队的敏捷性和创新。
4. 自治性
每个微服务都是自治的,拥有自己独立的数据存储和业务逻辑。这种自治性使得服务之间的耦合度降低,从而提高了系统的鲁棒性。
5. 轻量级通信
微服务之间的通信通常是轻量级的,常用的协议有HTTP/REST、gRPC、AMQP等。这些协议以其跨平台和灵活性著称,适合复杂分布式环境下的服务交互。
微服务的优势
和传统的单体架构,微服务存在以下优势:
- 可扩展性:由于微服务架构将应用拆分成多个小型服务,每个服务可以根据负载进行单独扩展。这使得系统具备高扩展性和高并发处理能力。
- 灵活性和敏捷性:微服务架构允许团队按照自身的需要选择适合的技术栈,并独立进行开发和部署。这种灵活性加快了产品的迭代速度,增强了系统对业务变化的敏捷响应能力。
- 故障隔离:在一个微服务体系下,如果某个服务出现故障,理论上只会影响到该服务的功能,而不会导致整个系统的瘫痪。这样有助于系统的稳定性和可靠运行。
- 技术多样性:微服务架构允许各个服务采用不同的技术栈进行开发,这意味着可以为不同的服务选择最适合的框架、语言和工具,优化各个服务的开发效率和性能。
如何搭建?
技术栈和场景
本文,我们将通过下面的技术栈来讲解如何搭建一套微服务架构:
- Spring Boot:用于构建微服务的基础框架。
- Spring Cloud:用于实现服务治理、配置管理和负载均衡。
- Eureka:用于服务注册和发现。
- Feign:用于服务间通信。
- Ribbon:用于客户端负载均衡。
- Hystrix:用于服务容错处理。
场景:设计一个简单的订单管理系统,该系统包含以下微服务:
- Eureka Server:Eureka Server是服务注册中心,各个微服务将自身注册到Eureka Server,其他服务通过Eureka Server发现这些服务。
- Order Service:订单服务,用于处理订单相关操作。
- User Service:用户服务,用于处理用户相关操作。
整个模型如下:
实现步骤
Eureka Server
Eureka 是服务注册中心,它是微服务架构中的核心组件,用于提供服务注册与发现的功能。Eureka之间是 Peer to Peer 的关系,其核心原理如下图:
- 创建一个Spring Boot项目并添加 Eureka Server依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 在主应用类中启用Eureka Server:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
- 配置
application.yml
:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
wait-time-in-ms-when-sync-empty: 0
Order Service
接着,创建一个订单服务,订单服务负责处理订单的创建、更新和查询等操作。
- 创建一个Spring Boot项目并添加Eureka Client依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 在主应用类中启用Eureka Client:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
- 配置
application.yml
:
server:
port: 8081
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
- 实现订单控制器:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@GetMapping("/orders/{orderId}")
public String getOrder(@PathVariable String orderId) {
return "Order details for order id: " + orderId;
}
}
User Service
接着,创建一个用户服务,用户服务负责处理用户的创建、更新和查询等操作。
实现步骤
-
创建一个Spring Boot项目并添加Eureka Client依赖(与订单服务相同)。
-
在主应用类中启用Eureka Client(与订单服务相同)。
-
配置
application.yml
:
server:
port: 8082
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
- 实现用户控制器:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@GetMapping("/users/{userId}")
public String getUser(@PathVariable String userId) {
return "User details for user id: " + userId;
}
}
服务间通信
在微服务架构中,服务间通信是必不可少的。我们将使用 Feign进行服务间通信。Feign是一个声明式的HTTP客户端,可以简化HTTP API的调用。通过Feign,我们可以像调用本地方法一样调用远程服务。
在订单服务中调用用户服务
- 添加Feign依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 启用Feign客户端:
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
- 创建Feign客户端接口:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{userId}")
String getUser(@PathVariable("userId") String userId);
}
- 在订单控制器中使用Feign客户端:
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
private final UserClient userClient;
public OrderController(UserClient userClient) {
this.userClient = userClient;
}
@GetMapping("/orders/{orderId}")
public String getOrder(@PathVariable String orderId) {
String userDetails = userClient.getUser("123");
return "Order details for order id: " + orderId + ", User Details: " + userDetails;
}
}
负载均衡
Ribbon是 Spring Cloud Netflix提供的客户端负载均衡器,使用Feign时,Ribbon已经默认集成,因此无需额外配置。
熔断器
Hystrix是由 Netflix开源的一个库,用于处理分布式系统中的延迟和容错问题,它通过隔离服务之间的调用,防止故障在系统中蔓延,从而提高系统的弹性和稳定性。Hystrix的主要原理和功能如下:
1. 隔离和熔断
- 线程池隔离:Hystrix为每个依赖服务调用分配一个独立的线程池,这样即使某个服务调用出现问题(如响应缓慢或失败),也不会占用主应用程序的线程资源,从而影响其他服务的调用。
- 信号量隔离:除了线程池隔离,Hystrix还支持信号量隔离,通过限制并发调用的数量来实现资源隔离。
- 熔断器:类似于电路中的断路器,Hystrix的熔断器在检测到服务调用失败率超过设定阈值时,会暂时中断对该服务的调用。熔断器有三种状态:
关闭:正常状态,允许请求通过。 打开:当失败率超过阈值时,阻止请求通过,直接返回错误。 半开:经过一段时间后,允许部分请求通过以测试服务是否恢复。
2. 失败处理和降级
降级策略:当服务调用失败或熔断器打开时,Hystrix支持提供降级方法来返回默认值或执行备用逻辑。这确保了即使服务不可用,系统也能继续运行。
3. 监控和告警
- 实时监控:Hystrix提供了实时的监控功能,通过Hystrix Dashboard可以查看每个服务调用的成功、失败、超时、熔断等指标。
- 告警:通过集成监控系统,如Prometheus或Grafana,可以设置告警规则,及时通知运维人员处理异常。
4. 请求缓存和批量请求
- 请求缓存:Hystrix可以缓存相同请求的结果,以减少重复调用。
- 批量请求:支持将多个请求合并为一个批量请求,从而提高调用效率。
在Feign中使用Hystrix
- 添加Hystrix依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 启用Hystrix:
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
- 在Feign客户端中实现熔断器:
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/users/{userId}")
String getUser(@PathVariable("userId") String userId);
}
@Component
class UserClientFallback implements UserClient {
@Override
public String getUser(String userId) {
return "User service is currently unavailable.";
}
}
个人心得
工作多年,经历过多家互联网大厂,涉及过金融,电商和出行等领域,对于大厂而言,业务足够大,技术力量和技术人员也比较充沛,另外公司的基础服务也比较健全,因此,对于微服务架构有很成熟的技术方案,技术人员更多的还是关注于业务。
对于中小型的公司,不管是资金的考量,还是技术力量方面,要搭建和维护微服务架构都是一个很大的挑战,因此,绝大多数的小公司可能根本用不上微服务架构,对于其他一小部分公司,微服务架构很多时候是资金,技术和业务三方面的权衡结果。
总结
本文介绍了如何使用 Java,Spring Boot和Spring Cloud 构建一个简单的微服务架构,重点介绍了服务注册与发现、服务间通信、负载均衡和熔断器的实现。通过这个示例,我们可以了解到微服务架构的基本原理和实现过程。在实际应用中,我们可能需要根据具体需求对架构进行调整和优化,比如增加更多的微服务、使用分布式配置中心、链路追踪等功能。
微服务架构虽然带来了很多好处,但同时也引入了分布式系统的复杂性,因此在设计和实现时需要仔细权衡和考虑。
交流学习
最后,把猿哥的座右铭送给你:投资自己才是最大的财富。 如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注: 猿java,持续输出硬核文章。