1.分布式与微服务的关系
分布式和微服务是两个相关但不完全相同的概念,它们可以共同用于构建现代化的软件应用程序。
-
分布式系统: 分布式系统是指将多个独立的计算机或节点连接起来,通过网络进行通信和协作,以实现共同的目标。这些节点可以物理上分布在不同的地理位置。分布式系统的目标是通过分布处理提高系统的性能、可靠性、扩展性和可伸缩性。
-
微服务架构: 微服务是一种基于分布式系统的软件架构模式,其中应用程序被设计为一组小型、独立的服务,每个服务专注于完成特定的业务功能。每个微服务可以独立部署、扩展和升级,通过 API 进行通信。微服务架构的目标是通过服务化、独立部署、松耦合、高内聚等特性来提高系统的灵活性、可维护性和可伸缩性。
关系:
-
微服务是一种分布式系统的设计范例:微服务架构是一种特定的分布式系统设计范例,强调将应用程序划分为小型、独立的服务单元,每个单元都是一个独立的部署、运行和维护的服务。
-
微服务是分布式系统的一种实现方式:微服务架构是分布式系统的一种实现方式,通过将应用程序拆分成多个小型服务,每个服务独立运行,实现了分布式系统的目标。
总结来说,分布式系统是一种广泛的概念,它涵盖了系统中多个组件通过网络连接和协作的情况。而微服务是一种特定的分布式系统设计和实现方式,通过将应用程序拆分成小型、独立的服务来实现更灵活、可维护和可扩展的系统架构。
2.springcloud是什么?
Spring Cloud 是一个基于 Spring Boot 的开源微服务框架,它简化了在分布式系统中构建、部署和运行微服务应用程序的复杂性。Spring Cloud 提供了一组开箱即用的工具和库,用于解决分布式系统中的常见问题,如服务注册与发现、负载均衡、熔断、配置管理、API 网关等
目前接触的组件和用途:
nacos:用于服务注册和发现,也可作于配置中心nacosconfig
ribbon:负载均衡,减少一个服务的压力
feign:用于服务间调用,集成了ribbon
getway:网关,可以做断言(谓词)的各项定义
sleuth 和 zipkin :链路追踪 sleuth : 链路追踪器 zipkin:链路分析器(可视化)
sentinel:服务限流,降级和熔断
3.限流 降级 熔断 分别是针对自己还是上游还是下游
限流、降级和熔断是针对不同层次或方向的策略,它们可以在不同的位置和场景下应用:
-
限流(Rate Limiting):
- 针对上游(请求方):限流通常是在上游系统或客户端实施的,目的是控制上游系统向下游系统发送请求的速率。这可以防止上游系统发送过多的请求,从而导致下游系统过载。
- 例子:客户端对某个微服务的请求限制每秒发送的请求数。
-
降级(Fallback):
- 针对自己(服务自身):降级是在服务自身实施的策略,用于在服务出现异常或负载过高时关闭或替换某些功能,以确保核心功能仍然可用。
- 例子:服务自身在高负载情况下停用某些非关键功能,以确保关键功能的可用性。
-
熔断(Circuit Breaker):
- 针对下游(被调用的服务):熔断通常是在调用外部服务或依赖时实施的策略,用于监视下游服务的响应状态,当下游服务出现故障或响应缓慢时停止向其发送请求,从而防止对下游服务的连续请求。
- 例子:微服务A对微服务B的调用经过熔断器,当微服务B的错误率超过阈值时,熔断器会打开,停止向微服务B发送请求。
总结来说,限流通常是在请求方(上游)实施,降级通常是在服务自身实施,而熔断通常是在调用外部服务或依赖(下游)时实施。这些策略的目标是确保系统在不同情况下能够保持稳定性,防止异常情况传播到整个系统。它们可以单独使用,也可以组合在一起以提高系统的弹性和可靠性。
4.在注册中心,nacos和Eureka有何区别?
1.各自的介绍
一个Eureka中分为eureka server和eureka clint,其中eurka server是作为服务的注册与发现中心,eureka client既可以作为服务的生产者,又可以作为服务的消费者
Nacos是阿里巴巴最新开源的项目,提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。更敏捷和容易地构建、交付和管理微服务平台。
Nacos支持基于DNS和基于RPC的服务发现,动态配置服务(配置中心),动态DNS服务
2.区别
下面是 Nacos 和 Eureka 的主要区别:
-
单元功能:
- Nacos: Nacos 不仅是服务注册和发现中心,还是配置管理中心。它集成了服务注册、服务发现、配置管理和 DNS 动态解析等多种功能。
- Eureka: Eureka 主要用于服务注册和发现,不包含配置管理等功能。
-
配置管理:
- Nacos: Nacos 提供了配置中心,可以集中管理和动态更新微服务的配置信息,支持多种数据格式(如 JSON、YAML、Properties)。
- Eureka: Eureka 不包括配置管理功能。
-
多数据中心支持:
- Nacos: Nacos 支持多数据中心的配置和服务注册,适用于多地域、多区域的分布式部署。
- Eureka: Eureka 也可以支持多数据中心配置,但需要额外配置。
-
兼容性和社区活跃度:
- Nacos: Nacos 是阿里巴巴开源的项目,具有较好的兼容性和社区活跃度,得到了阿里巴巴的大力支持。
- Eureka: Eureka 最初是 Netflix 开源的项目,后来不再积极维护,继而 Apache 提供了 Netflix OSS 的替代品。
-
支持的编程语言:
- Nacos: Nacos 对多种编程语言提供了客户端 SDK,如 Java、Python、Go、Node.js 等。
- Eureka: Eureka 主要支持 Java。
-
集群模式:
- Nacos: Nacos 提供了多种集群模式,如单机模式、集群模式、多租户模式等。
- Eureka: Eureka 也支持集群部署。
综合来说,Nacos 拥有更丰富的功能,包括服务注册和发现、配置管理等,而 Eureka 主要专注于服务注册和发现。选择使用哪个取决于你的具体需求和团队的偏好。如果需要集成服务注册、发现、配置管理等多种功能,可以考虑使用 Nacos。如果只需要简单的服务注册和发现,可以选择 Eureka。
5.在微服务中常用的功能
1.Redis,缓存数据库,防止大量访问到数据库,导致的各种情况;或者热点访问快速返回数据等。具体内容前面的文章有写。可以直接用springboot集成之后使用。
2.mq中间件:消息队列,是一种常用的分布式消息通信解决方案,用于不同组件、系统或应用程序之间的异步通信。消息队列采用先进先出(FIFO)的原则,将消息从一个点传送到另一个点。
可以实现数据的最终一致性;
可以作为一个消息存储的数据库;
可以把系统的业务功能模块化,实现系统的解耦;
可以通过日志记录消息的发送和消费。可以打开控制台,然后网页8848,可以查看
可以使用 MQ 可以作为消息通讯的实现手段,利用它可以实现点对点的通讯或者多对多的聊天室功能
推荐文章:https://blog.csdn.net/lmfxiaohuo/article/details/126961120
Git的代码库如下:weifuwu: 一个微服务的demo
6.对于rocketmq的原理和使用描述
1.rocketmq完成分布式事务消息的过程
依赖半消息,二次确认以及消息回查机制。
1、Producer向broker发送半消息
2、Producer端收到响应,消息发送成功,此时消息是半消息,标记为“不可投递”状态,Consumer消费不了。
3、Producer端执行本地事务。
4、正常情况本地事务执行完成,Producer向Broker发送Commit/Rollback,如果是Commit,Broker端将半消息标记为正常消息,Consumer可以消费,如果是Rollback,Broker丢弃此消息。
5、异常情况,Broker端迟迟等不到二次确认。在一定时间后,会查询所有的半消息,然后到Producer端查询半消息的执行情况。
6、Producer端查询本地事务的状态
7、根据事务的状态提交commit/rollback到broker端。(5,6,7是消息回查)
半消息(半事务消息):是指暂时还不能被Consumer消费的消息,Producer成功发送到broker端的消息,但是此消息被标记为“暂不可投递”状态,只有等Producer端执行完本地事务后经过二次确认了之后,Consumer才能消费此条消息
2.mq和http的区别
-
通信方式:
- RocketMQ:RocketMQ 是一种基于消息队列的通信方式,通过消息队列实现消息的异步传递,支持发布/订阅模式和点对点模式。消息发送者将消息发送到消息队列,消息接收者从消息队列订阅并消费消息。
- HTTP:HTTP 是一种基于请求-响应模式的通信方式,客户端向服务器发送请求,服务器响应相应的数据。
-
模型:
- RocketMQ:RocketMQ 采用发布/订阅模型和点对点模型,可以实现一对多和多对多的通信模式。
- HTTP:HTTP 采用请求-响应模型,通常是一对一的通信模式。
-
实时性:
- RocketMQ:RocketMQ 通常具有较高的实时性,消息可以实时地被消费者处理。
- HTTP:HTTP 请求需要一定的网络传输时间,实时性可能略逊于消息队列。
-
传输方式:
- RocketMQ:RocketMQ 通常基于 TCP 协议传输消息,提供高效、可靠的消息传输。
- HTTP:HTTP 通常基于 TCP 协议传输数据,但它是一种应用层协议,相对于消息队列可能会增加一些额外的开销,例如 HTTP 头部信息。
-
持久性:
- RocketMQ:RocketMQ 提供消息的持久性,可以在消息队列中持久化消息,确保消息不会丢失。
- HTTP:HTTP 请求-响应本身不具有消息的持久性,但可以通过应用程序的逻辑来保证数据的持久性。
-
适用场景:
- RocketMQ:适用于分布式系统、微服务架构、异步通信、事件驱动等场景,特别是对实时性要求较高的场景。
- HTTP:适用于前后端通信、API 调用、Web 服务等场景,也适合实现简单的异步通信,但相对于消息队列可能不适用于高频率、大量数据的异步通信
此文章还写到了http协议与RPC协议以及MQ之间的一些关系
https://blog.csdn.net/qq_34020761/article/details/132521731
3.代码实现(需要安装好rocketmq且打开,然后打开rocketmq的前端控制器。或者虚拟机安装了也OK)
1.依赖
<!-- rocketmq 的依赖-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
2.配置
rocketmq:
name-server: 127.0.0.1:9876 #rocketMQ服务的地址
producer:
group: shop-order # 生产者组
3.尝试发送一个简单消息SandMassageTest
package com.dgy.system.rocketmq;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
public class RocketMQSandMassageTest {
//发送消息
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
//1.创建消息生产者并且设置生产者组名
DefaultMQProducer producer = new DefaultMQProducer("myproduct-group");
//2.为生产者设置nameServer的地址
producer.setNamesrvAddr("192.168.2.170:9876");
//3.启动生产者
producer.start();
//4.构建消息对象,主要是设置消息的主题、标签、内容
Message message = new Message("myTopic", "myTag", ("Test RocketMQ Message").getBytes());
//5.发送消息
SendResult result = producer.send(message, 10000);
System.out.println(result);
//6.关闭生产者
producer.shutdown();
}
}
4.接收消息
package com.dgy.system.rocketmq;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
//接收消息
public class RocketMQReceiveTest {
public static void main(String[] args) throws MQClientException {
//1. 创建消息消费者, 指定消费者所属的组名
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myconsumer-group");
//2. 指定Nameserver地址
consumer.setNamesrvAddr("localhost:9876");
//3. 指定消费者订阅的主题和标签
consumer.subscribe("myTopic","*");
//4. 设置回调函数,并在函数中编写接收到消息之后的处理方法
consumer.registerMessageListener(new MessageListenerConcurrently() {
//处理获取到的消息
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
//消费的逻辑
System.out.println("message===>"+list);
//返回消费成功
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//5. 启动消息消费者
consumer.start();
System.out.println("启动消费者成功了");
}
}
5.了解mq可以发送的其他消息
-
简单消息(普通消息)(Simple message):
- 简单消息是最常见的消息发送方式,发送者通过发送消息到指定的消息主题(Topic),然后消费者从该主题中订阅消息并处理。
- 简单消息具有一对多的发布/订阅特性。
-
顺序消息(Sequential message):
- 顺序消息保证一组消息按照发送顺序被消费。RocketMQ 提供了顺序消息的支持,可以通过指定消息队列或者消息队列选择器来实现消息的顺序处理。
-
事务消息(Transaction message):
- 事务消息保证消息的可靠传递和处理,同时允许发送者在发送消息后进行事务性操作。如果事务性操作成功,消息将被提交,否则将被回滚。
- 事务消息的发送分为两阶段:提交或回滚。在第一阶段,消息发送到 RocketMQ 服务器,并存储为预备消息;在第二阶段,根据发送结果执行提交或回滚操作。
-
批量消息(Batch message):
- 批量消息允许发送者将多条消息合并成一个消息进行发送,以减少网络开销和提高效率。
-
延迟消息(Delayed message):
- 延迟消息允许发送者指定消息的延迟时间,在指定的延迟时间后,消息才会被消费者接收和处理。
6.使用redistemplate来进行消息发送
package com.dgy.system.controller;
import com.alibaba.fastjson.JSON;
import com.dgy.entity.Orders;
import com.dgy.entity.Product;
import com.dgy.system.service.ProductService;
import com.dgy.system.service.impl.OrdersServicelmpl4;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/system/orders2")
@Slf4j
public class OrderControllermq {
@Resource
private ProductService productService;
// @Resource
// private OrdersServiceImpl ordersService;
@Resource
private OrdersServicelmpl4 ordersServicelmpl4;
@Resource
RocketMQTemplate rocketMQTemplate;
//下单fegin
@RequestMapping("/prodmq/{pid}")
public Orders prod(@PathVariable("pid") Integer pid) {
//原始的调用product的地址
log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息",pid);
//调用商品微服务查询商品信息
Product product = productService.findbyid(pid);
log.info("查询到{}号商品的信息,内容是:{}",pid, JSON.toJSONString(product));
//下单(创建订单)
Orders orders = new Orders();
orders.setUid(2);
orders.setUsername("BBB");
orders.setPid(pid);
orders.setPname(product.getPname());
orders.setPprice(product.getPprice());
orders.setNumbers(1);
System.out.println(orders.toString()+"======================================================");
// ordersService.save(orders);
log.info("创建订单成功,订单信息为{}", JSON.toJSONString(orders));
//向MQ中投递一个下单成功的消息
//参数一是指定topic
//参数二是指定消息体
rocketMQTemplate.convertAndSend("order-topic",orders);
ordersServicelmpl4.createOrderBefore(orders);
return orders;
}
}