1、Eureka的作用
如上图,order-service为服务的消费者,user-service为服务的提供者,那么user-service需要将自己的信息如ip地址以及端口号上传的eureka-server注册中心,注册中心保存着user-service的ip和端口信息。
因为order-service也可能被其他服务调用,所以也会上传到注册中心。这样注册中心就保存了两个微服务的IP和端口号。
order-service会定期的从注册中心拉取信息,将其保存到自己服务的本地中,这样就可以通过feign和使用Ribbon利用负载均衡实现对某一实例的远程调用。
user-service会30秒发送一次心跳给注册中心,当user-service中的某一台服务宕机的时候,并且注册中心90秒内未收到心跳,那么就会认为某一台实例宕机了,就会从注册中心中删除宕机的实例。并且user-service会定期从注册中心拉取服务信息,更新自己的本地信息表。
首先是nacos的流程:
不同:
Nacos与eureka的共同点 (注册中心)
Nacos与Eureka的区别 (注册中心)
Nacos还支持了配置中心,eureka则只有注册中心,也是选择使用nacos的一个重要原因
三、 你们项目负载均衡如何实现的?
1、Ribbon负载均衡流程
首先是order-service调用user-service。那么就会通过url地址发起请求,在这个请求的中间会调用Feign这个组件(内置Ribbon),Feign会从注册中心拉取user-service的IP地址和端口号,然后注册中心会将user-service的IP地址和端口号返回给Feign,这样Feign就知道了user-service的IP地址和端口号。Feign里面内置了Ribbon,因此根据不同的策略进行对user-service的远程调用。Ribbon默认为轮询策略。
2、Ribbon负载均衡策略有哪些?
可以自己创建类实现IRule接口,然后再通过配置类或者配置文件配置即可,通过定义IRule实现可以修改负载均衡规则,有两种方式:
如果在某一时刻,服务B出现故障(可能就卡在那里了),而这时服务A依然有大量的请求,在调用服务B,那么,由于服务A没办法再短时间内完成处理,新来的请求就会导致线程数不断地增加,这样,CPU的资源很快就会被耗尽。那么就会出现服务雪崩。
部分服务不可以
如上图,如果正常调用失败的话,那么就会采用备用的回答来返回结果。
所有服务不可以
如上图,为服务熔断的流程。根据熔断策略,当服务调用失败到一定的次数,就会触发熔断机制,首先打开熔断器,所有请求全部降级处理。当熔断时间结束(Sentinel和Hystrix相同),会尝试进行放行一次请求查看是否成功,如果失败就继续全部降级处理,直到成功后关闭熔断。
慢调用比例
判定为慢调用条件:一次请求的响应时间超过最大RT值,那么就是慢调用。
即:在一个统计时长内,如果请求数目大于最小请求数目,并且被判定为慢调用
的请求比例已经超过阈值,将触发熔断
如上图,如果在1000ms内,当请求超过1次请求,并且请求时间超过500ms占每1次请求的100%就会触发5秒熔断
异常比例
如上图,在1秒内当每2次请求中异常比例达到1的时候 ,那么就会触发5秒熔断时间。
异常数
如上图,在1秒内当每2次请求中异常数为1的时候 ,那么就会触发5秒熔断时间。
什么是服务雪崩,怎么解决这个问题?
事务机制和 confirm 机制最大的不同在于,事务机制是同步的,你提交一个事务之后会阻塞在那儿,但是 confirm 机制是异步的。
RabbitMQ支持消费者确认机制,即: 消费者处理消息后可以向MQ发送ack回执,MQ收到ack回执后才会删除该消息,而SpringAMQP则允许配置三种确认模式:
在生产者开启了confirm模式之后,每次写的消息都会分配一个唯一的id,然后如果写入了rabbitmq之中,rabbitmq会给你回传一个ack消息,告诉你这个消息发送OK了;如果rabbitmq没能处理这个消息,会回调你一个nack接口,告诉你这个消息失败了,你可以进行重试。而且你可以结合这个机制知道自己在内存里维护每个消息的id,如果超过一定时间还没接收到这个消息的回调,那么你可以进行重发。
对于如何重发消息有以下方法:
使用消息持久化来解决RabbitMQ弄丢了数据这个问题。
要想做到消息持久化,必须满足以下三个条件,缺一不可:
多个消费者同时收取消息,比如消息接收到一半的时候,一个消费者死掉了(逻辑复杂时间太长,超时了或者消费被停机或者网络断开链接),如何保证消息不丢?
有三种确认方式:
其中自动确认是指,当消息一旦被Consumer接收到,则自动确认收到,并将相应 message 从 RabbitMQ 的消息缓存中移除。
但是在实际业务处理中,很可能消息接收到,业务处理出现异常,那么该消息就会丢失。如果设置了手动确认方式,则需要在业务处理成功后,调用channel.basicAck(),手动签收,如果出现异常,则调用channel.basicNack()方法,让其自动重新发送消息。
造成重复消费的原因:
如上图,当consumer将队列中的消息并处理以后准备发送确认ACK的时候,突然宕机了,导致队列没有收到ACK,消费过的消息没有在队列中删除。但是由于有重试机制,导致consumer再次从队列中获取消息,这样就会导致重复消费。
解决方法:
延迟队列=死信交换机+TTL
延迟队列:进入队列的消息会被延迟消费的队列
场景:超时订单、限时优惠、定时发布
如上图,应用场景为超时订单,这个时候可以使用延时队列来处理。当下完订单以后,然后将消息发送给延时队列,30分钟以后该消息才可以被支付系统获取去检查是否成功支付。
当一个队列中的消息满足下列情况之一时,可以成为死信 (dead letter):
如果该队列配置了dead-leter-exchange属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,简称DLX)。
如上图,当生产者发布一条消息给交换机并路由到另一个队列的时候,由于消费者拒绝了该消息,就会导致该消息成为死信不能被消费只能进入私信交换机路由到死信队列让其他消费者消费该消息。
TTL,也就是Time-To-Live。如果一个队列中的消息TTL结束仍未消费,则会变为死信,tl超对分为两种情况:
如上图,生产者发布了一条消息,这个消息的存活时间为5000ms,但是消息队列也设置了存活时间为10000ms,由于RabbitMQ规定二者谁的存活时间短就以谁为准。当TTL到期以后,然后消息回进入死信交换机路由到死信队列,与死信队列绑定的消费者就会消费这条消息。
如上图,当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题。
对于扩大队列的容积,使用的是惰性队列