面试题答案
一键面试基于Node.js的Express框架设计简单微服务架构
- 设计微服务:
- 用户服务:负责处理用户相关的业务逻辑,例如用户注册、登录、信息修改等。可以使用Express创建路由,如
/users/register
用于用户注册,/users/login
用于用户登录等。 - 订单服务:处理订单相关的操作,像订单创建、查询、取消等。同样通过Express创建路由,如
/orders/create
用于创建订单。
- 用户服务:负责处理用户相关的业务逻辑,例如用户注册、登录、信息修改等。可以使用Express创建路由,如
- 通信方式:
- RESTful API:这是一种常用的微服务间通信方式。例如订单服务在创建订单时可能需要调用用户服务来验证用户信息。订单服务可以向用户服务的
/users/check
这样的API发送HTTP请求,获取用户是否合法的信息。这种方式简单直观,易于理解和实现,基于HTTP协议,通用性强。 - 消息队列:比如在处理一些异步任务时可以使用消息队列。假设订单创建成功后需要发送通知,订单服务可以将通知消息发送到消息队列(如RabbitMQ、Kafka等),通知服务从队列中消费消息并执行发送通知的操作。这样可以解耦服务,提高系统的可扩展性和性能。
- RESTful API:这是一种常用的微服务间通信方式。例如订单服务在创建订单时可能需要调用用户服务来验证用户信息。订单服务可以向用户服务的
- 服务发现与注册:
- 使用Consul:
- 服务注册:每个微服务在启动时,向Consul注册自己的信息,包括服务名称、IP地址、端口等。例如用户服务启动时,通过Consul的HTTP API将自身信息注册到Consul服务器。
- 服务发现:当一个微服务需要调用另一个微服务时,它向Consul查询目标服务的地址。比如订单服务要调用用户服务,订单服务向Consul询问用户服务的IP和端口,Consul返回相关信息,订单服务即可发起请求。
- 使用Eureka:
- 服务注册:微服务将自身信息注册到Eureka Server,Eureka Server维护一个服务注册表。
- 服务发现:其他微服务通过向Eureka Server查询来获取所需服务的实例列表,从而实现服务间的调用。
- 使用Consul:
- 保证数据一致性:
- 分布式事务:如果涉及多个微服务间的数据操作需要保证一致性,可以使用分布式事务框架,如Seata。以订单创建为例,订单服务创建订单记录,库存服务扣减库存,在Seata的协调下,要么所有操作都成功提交,要么都回滚,保证数据的一致性。
- 最终一致性:对于一些对一致性要求不是特别高的场景,可以采用最终一致性方案。比如订单创建成功后,库存服务扣减库存失败,此时可以通过消息队列将扣减库存的任务重试或者记录下来后续人工处理,最终保证库存数据的一致性。
- 保证系统可靠性:
- 负载均衡:在微服务架构前端使用负载均衡器(如Nginx、HAProxy等)。将请求均匀分配到各个微服务实例上,避免单个实例压力过大导致服务不可用。例如多个用户服务实例,负载均衡器可以根据算法(如轮询、IP哈希等)将用户请求分配到不同的实例。
- 容错机制:
- 超时设置:在微服务调用时设置合理的超时时间。如订单服务调用用户服务验证用户信息,如果用户服务在一定时间内未响应,订单服务可以中断等待并返回错误信息,避免长时间等待影响用户体验。
- 重试机制:当微服务调用失败时,可以设置重试策略。比如调用库存服务扣减库存失败,订单服务可以重试一定次数,提高操作成功的概率。
- 监控与报警:使用监控工具(如Prometheus、Grafana等)对微服务的各项指标(如CPU使用率、内存使用率、请求响应时间等)进行监控。当指标超出正常范围时,通过报警系统(如Alertmanager)及时通知运维人员,以便快速处理问题,保证系统的可靠性。