spring微服务系列(二)服务间简单的通信以及熔断

目录

  • 首语
  • Feign
    • 引入feign
    • 接口
    • 思考
      • Feign调用原理
      • rpc远程接口调用
  • Hystrix熔断
    • 接口
    • feign接口fallback
    • 测试与配置
  • 结束

首语

博主老规矩,先写一个首语

spring系列微服务通信以rest为主,2.0以下版本以eureka做服务注册中心为主,2.0以上eureka不在维护,博主团队使用了阿里的Nacos。在博主上一篇博客已经简单的介绍了从0到1搭建一个项目,然后注册在eureka上。

注意:博主不会公开企业级内部的代码,博主会将它变成比较简单的demo,提供设计思想,供大家学习。因为每个企业或者团队思想差异,会造成框架与流程也变得不一样。企业级的代码反倒会变得臃肿~

Feign

spring微服务系列如果是MVC同步式变成,几乎在通信层面都会使用Feign组件(在异步webflux方面使用webclinet)

我们首先创建两个项目, demo-one与demo-two

引入feign

我们引入feign的组件包,顺便将测试包也引入


        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

接口

我们来为demo-one写一个hello world接口

 @GetMapping("/say/hello")
    public String sayHello() {
        return "hello world";
    }

我们在demo-two中写相应的feign接口以及测试类(关于api抽离,后续博主会为搭建展现,目前只是简单介绍一些组件的使用,后续会涉及到组件包抽离、自定义starter、全程异步话webflux企业运用等)

// demo-one的服务名是DEMO-ONE
@FeignClient(name = "DEMO-ONE")
public interface DemoOneApi {

    @GetMapping("/say/hello")
    public String sayHello();
}

然后我们来编写一个简单的测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Boot.class)
@EnableFeignClients(basePackages = {"com.github.codemperor.demo.two"}) //这一行需要加哦~
public class FeignTest {
    @Autowired
    private DemoOneApi demoOneApi;

    @Test
    public void demoOneFeignTest() {
        System.out.println(demoOneApi.sayHello());

    }
}

然后我们启动eureka以及demo-one

运行测试类,发现打印hello word,说明两个服务通信成功

思考

我们来思考一个很重要的问题:

多服务通信的时候,我们在demo-two中拷贝了demo-one的接口(有点类似dubbo rpc),然后利用interface进行通信,那么问题来了:

  • 如果接口源头改变,我们是否也得跟着修改feign interface,如果多方调用同一个源头,那么是否全部都得改,如果提取api,如何提取?如何集中管理api?
  • 接口注入,底层是如何实现调用对方的rest?和dubbo这样的rpc(grpc)有什么区别?

一般情况下,部分小公司会直接提取一个api(参考博主的code项目),变成一个jar,但这样的方式,不够自动化,所以需要一些api scan机制,配合网关集中管理所有api。
至于底层实现原理,和rpc是不同的:

Feign调用原理

这里就不画图了,feign只是封装的调用层,在开始调用的时候,feign会去获取调用目标地址,然后直接
http://xx.xx.xx.xx/say/hello

rpc远程接口调用

以java远程socket作为最底层通信协议,那么rpc其实利用的是序列化以及反射原理。为什么要拷贝接口,是因为需要获取接口信息,简单来说,如果知道class信息以及方法名称,就可以利用java反射来执行方法。

那么我们可以模拟这个过程:

@RunWith(SpringJUnit4ClassRunner.class)
public class RpcTest {

    @Test
    public void rpcTest() throws Exception {

        // 第一个参数是类,第二个是执行方法, 第二个是参数
        var fromClient = List.of("com.github.codemperor.demo.one.bean.RemoteBean", "sayHello", "你好呀");
        var clazz = Class.forName(fromClient.get(0));
        // 为了不暴漏接口序列化的信息,我们可以设定协议,比如A代表了RemoteBean这个类,那就变成:
        if ("A".equalsIgnoreCase(fromClient.get(0))) {
            var clazz1 = RemoteBean.class;
            // 后面使用class1
        }
        Object ob = clazz.getDeclaredConstructor().newInstance();
        Method method = clazz.getMethod(fromClient.get(1), String.class);
        method.invoke(ob, fromClient.get(2));
    }
}

所以这里就涉及到rpc的通信协议。我们可以利用netty等底层通信框架(或者java socket)来模拟一次rpc过程。

Hystrix熔断

这里要明确一点,feign不是hystrix,只是对它进行了简易的封装,依然考的是反射等底层机制

接口

我们先来写一个接口,并且让它睡5秒

@GetMapping("/feign/fallback")
    public String sayFeignFallback() throws InterruptedException {
        Thread.sleep(5000);
        return "say feign fallback";
    }

feign接口fallback

然后和上面一样,在demo-two中把这个接口弄过来,然后加上fallback机制

@FeignClient(name = "DEMO-ONE", fallbackFactory = DemoOneApiFallback.class)
public interface DemoOneApi {

    @GetMapping("/say/hello")
    public String sayHello();

    @GetMapping("/feign/fallback")
    public String sayFeignFallback();
}

可以看到,我们加入了DemoOneApiFallback作为熔断降级后的业务处理(这里注意一点,如果降级后,还需要继续调用另外的服务,另外的服务也GG了,然后又回到熔断这里,形成死循环,这个时候你可能会被打死)

@Component
public class DemoOneApiFallback implements FallbackFactory {
    @Override
    public DemoOneApi create(Throwable throwable) {
        return new DemoOneApi() {
            @Override
            public String sayHello() {
                return null;
            }

            @Override
            public String sayFeignFallback() {
                return "对方挂了斯密达, 我先回一个~~";
            }
        };
    }
}

测试与配置

demo-two调用demo-one, 自然demo-two要开启feign的熔断,我们这里设定3秒内不回答就gg:
时间的设定(nacos可以直接利用timeout机制实时pull的方式,可以动态修改各种配置(配置中心也可以)),需要根据业务以及网络架构延时来制定,比如博主digital团队是小业务,所以业务一般在接口级,而接口都是云内网调用,一般即使加上数据库,也只有50ms,所以博主这边设置1s内获取不到就等于超时,走熔断~

feign:
  client:
    config:
      default:           #服务名,填写default为所有服务
        connectTimeout: 10000
        readTimeout: 10000
  hystrix:
    enabled: true
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

我们来写一个测试接口,demo-one接口设定5秒内返回,熔断设定3秒内不回答就走熔断:

@Test
    public void demoOneFeignFallbackTest() {
        System.out.println(demoOneApi.sayFeignFallback());
    }

结果果然走了熔断,修改熔断时间,变为10秒,发现走了接口返回

结束

这一篇博客依然是从0到1搭建以及理解的基础知识(感觉博主自己坑了自己)
后续鉴权中心、网关设定、核心包sdk抽离感觉遥遥无期啊~~博主抓紧结束基础篇。
附上学习代码:https://gitee.com/_madi/codemperor.git

你可能感兴趣的:(后端,springboot,java)