1、Feign远程调用如何实现?服务不可用熔断如何实现?
简介 Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
实现步骤:
(1)导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--由于feign整合了ribbon的负载均衡,所以需要引入ribbon的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!--需要从eureka拉取服务-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
(2)启动类添加注解支持
@EnableFeignClients
(3)客户端编写
//定义接口
package com.sun.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(value = "user-service") //声明这是feign的客户端
public interface UserFeignClient {
@GetMapping("user")
public String getUser();
}
注释:这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像@FeignClient,声明这是一个Feign客户端,类似@Mapper注解。同时通过value属性指定服务名称接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果改造原来的调用逻辑,不再调用UserDao:
//实现调用
@Autowired
private UserFeignClient userFeignClient;
@GetMapping("feign")
public Object feign(){
return userFeignClient.getUser();
}
(4)feign自动实现负载均衡
(5)feign的重试
#feign的重试与ribbon的配置相同,只要添加相应的配置即可。
client:
ribbon:
MaxAutoRetries: 1 #配置首台服务器重试1次
MaxAutoRetriesNextServer: 2#配置其他服务器重试两次
ConnectTimeout: 500 #链接超时时间
ReadTimeout: 2000 #请求处理时间
OkToRetryOnAllOperations: true #每个操作都开启重试机制
(6)feign与hystrix的集成配置熔断机制
1)添加熔断配置
feign:
hystrix:
enabled: true #允许熔断
2)添加熔断处理类
实现 UserFeignClient接口
3)实现调用
2、服务内如何进行接口调用?
Requestmaping方式调用
21、JVM底层原理
3、消息队列重复消费问题?
幂等性(如何避免消息的重复消费) 概述:可能因为各种原因,导致了生产端发送了多条一样的消息给消费端,但是,消费端也只能消费一条,不会多消费。
(1)唯一ID + 指纹码机制
指纹码(就是时间戳 + 业务的一些规则, 来保证id + 指纹码在同一时刻是唯一的,不会出现重复)
唯一ID + 指纹码机制,利用数据库主键去重;
select count(1) from t_order where id = 唯一ID + 指纹码;
好处:实现简单;
坏处:高并发下有数据库写入的瓶颈;
解决方案:跟进ID进行分库分表进行算法路由;
(2)利用Redis的原子性实现
存在的问题:
我们是否需要进行数据的持久化,若需要持久化,怎么保证数据库和redis做到原子性? 若不立即持久化,都存储到redis中,如何设置同步策略?
(3)设置前置条件
加一个版本号控制。
消息队列出现错误消息怎么办?
4、RabbitMQ
RabbitMQ简介
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
组件
Vhost
5、分布式如何保证消息一致性?
发送方确认消息机制
采用最终一致性原理
需要保证以下三要素:
a、确保生产者一定要将数据投递到MQ服务器中(采用MQ消息确认机制)。
b、确保消费者能够正确消费消息,采用手动ACK模式(注意重试、幂等性问题)。
c、如何保证第一个事务先执行,采用补偿机制,在创建一个补单消费者进行监听,如果订单没有创建成功,进行补单。(如果第一个事务中出错,补单消费者会在重新执行一次第一个事务,例如第一个事务是添加订单表,如果失败在补单的时候重新生成订单记录,由于订单号唯一,所以不会重复)。
6、如何设置事务不被Spring管理?
@Transactional,表示该类受Spring事务管理。如果该类中每个方法不需要事务管理,则在该方法前加入下面的Java代码 :
@Transactional(propagation=Propagation.NOT_SUPPORTED)
7、List遍历随机删除一个会发生什么?
fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
简单来说是java为了防止出现并发异常的一个机制,但是其实在单线程下也可以产生。 多线程操作list的话建议使用CopyOnWriteArrayList,或者对迭代器加锁。