项目搭建

详细请看思维脑图:https://www.processon.com/view/link/5ea01208f346fb177b8c9524

先创建父maven项目,只需导入spring cloud依赖,其他的依赖于之前springboot一样

具体项目结构已经放到码云上了

码云链接:https://gitee.com/liyitian/spring-cloud-ntiflix-exercise

     <!--spring Cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
              </dependency>

Eureka

个人理解】Eureka就是一个就是一个服务注册中心,所有服务通过它来做一个中加入进行注册或调用。可以搭建Eureka集群,如果一个注册中心挂了,还可以同过其他的组成中心访问。

】Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

他主要包含两个组件:Eureka Service 和 EurekaClient

  • Eureka Client:一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)
  • Eureka Server:提供服务注册和发现的能力(通常就是微服务中的注册中心)

推荐:https://www.cnblogs.com/jing99/p/11576133.html

步骤

导入依赖:

1、注册中心的依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

2、提供者服务端依赖:

     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

编写配置:

1、注册中心配置:

server:
  port: 7002

#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #Eureka服务端的示例名称
  client:
    register-with-eureka: false #表示是否向eureka注册中心注册自己 注册中心不需要注册自己
    fetch-registry: false #如果为flase则表示自己为注册中心
    service-url: #监控页面
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/ #修改监控页面默认地址

2、提供者服务端配置:

#Eureka的配置 把服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept8001  #修改eureka的默认Status描述信息

#info配置自定义信息
info:
  app.name: li-springcloud
  company.name: liyitian

打开Eureka

1、注册中心开启:

//启动之后访问 http://localhost:7001
@SpringBootApplication
@EnableEurekaServer //服务端的启动类,可以接受别人注册进来
public class Eureka_7002 {
    public static void main(String[] args) {
        SpringApplication.run(Eureka_7002.class,args);
    }
}

2、开启提供者服务端:

@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中!
@EnableDiscoveryClient //服务发现
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

Ribbon

\Ribbon是一个为客户端提供负载均衡功能的服务,它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。**

Ribbon是什么?
    Ribbon是Netflix发布的云中间层服务开源项目,其主要功能是提供客户端实现负载均衡算法。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。

步骤

1、导入依赖

   <!--ribbon于eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

2、编写配置

server:
  port: 80

#Eureka
eureka:
  client:
    register-with-eureka: false  #消费者不用向Eureka注册自己
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

3、开启Ribbon于Eureka客户端功能

//Ribbon 与 Eureka 整合后,客户端可以直接调用服务,不需要关心服务地址
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})//DataSourceAutoConfiguration.class阻止Spring boot自动注入dataSource
@EnableEurekaClient
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = LiRuble.class) //扫描自定义ribbon
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

4、配置 RestTemplate 模板Bean设置注解 @LoadBalanced Ribbon负载均衡

@Configuration
public class ConfigBean {
    //配置负载均衡失效RestTemplate
    //IRule
    //AvailabilityFilteringRule:先过滤掉,跳闸或服务故障的服务-对剩下的进行轮询
    //RoundRobinRule: 轮询 轮流访问服务
    //RandomRule : 随机
    //RetryRule :会先按照轮询获取服务,如果服务获取失败,则会在指定的时间进行 重试
    @Bean
    @LoadBalanced //使用Ribbon负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

5、消费者调用服务

@RestController
public class DeptConsumerController {
    //理解:消费者,不应该有service层
    //RestTemplate ...供我们调用
    @Resource
    private RestTemplate restTemplate; //提供多种便捷访问服务的方法,简单的restful服务模板

    //通过Ribbon进行负载均衡,这里的地址应该是一个变量,这个变量就是服务注册中心的服务的ID,通过服务ID来访问
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT/"; //提供者

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"dept/add",dept,Boolean.class);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept deptAdd(@PathVariable long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"dept/get/"+id,Dept.class) ;
    }

    @RequestMapping("/consumer/dept/list")
    @ResponseBody
    public List<Dept> list(){java
        return restTemplate.getForObject(REST_URL_PREFIX+"dept/list",List.class);
    }
}

总结:都是调用注解进行配置,非常的简单。

如果需要改变访问服务的方式我们可以配置它的访问方式。

步骤

1、首先在主启动类所在的包同级创一个放IRule的包,记住是主启动类所在的包同级

2、然后创建一个类,用来改变访问服务的方式

@Configuration
public class LiRuble {
    @Bean
    public IRule myIRule(){
        return new LiRandomRule(); //默认是轮询,现在是自定义
    }
}

3、也可以根据自己的需求,自定义一个服务方式的类,如下:

public class LiRandomRule extends AbstractLoadBalancerRule {
    /*
        每个机器访问五次,换下一个服务(有3个服务)
        total=0,默认=0如果=5,就指向下一个服务节点
        index=0 默认=0,如果total=5 index+
     */
    private int total = 0;//一个服务被调用的次数
    private int currentIndex = 0;//当前是谁在提供服务

    // @edu.umd.classs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();//获得活着的服务
            List<Server> allList = lb.getAllServers();//获得所有服务

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

//            int index = chooseRandomInt(serverCount);//生成区间随机数
//            server = upList.get(index);//从活着的服务中,随机获得一个
            //==========================================================
            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex >= upList.size()) {
                    currentIndex = 0;
                }
              server = upList.get(currentIndex);  //从活着的服务中,获取指定的服务来进行操作
            }
            //==========================================================
            if (server == null) {
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub

    }
}

Feign

个人理解】与Ribbon一样负载均衡功能,去呗是Feign跟符合接口调用编程,Ribbon是用调用链接,Feign也使用了Ribbon,只是进行封装,可以使我们直接调用接口。

】feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。

步骤

1、导入依赖feign

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

2、编写feign服务

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptServiceFallbackFactory.class)
 public interface DeptClientSerivce {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") long id);
    @GetMapping("/dept/list")
    public List<Dept> queryAll();
    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

}

3、调用这个服务

@RestController
public class DeptConsumerController {
    @Autowired
    DeptClientSerivce deptClientSerivce = null;
    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return this.deptClientSerivce.addDept(dept);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept getDept(@PathVariable Long id){
        return deptClientSerivce.queryById(id) ;
    }

    @RequestMapping("/consumer/dept/list")
    @ResponseBody
    public List<Dept> list(){
        return deptClientSerivce.queryAll();
    }
}

Hystrix

个人理解】在微服务场景中,通常会有很多层的服务调用。如果一个底层服务出现问题,故障会被向上传播给用户。我们需要一种机制,当底层服务不可用时,可以阻断故障的传播。这就是断路器的作用。他是系统服务稳定性的最后一重保障。

熔断功能

它是设置在服务端

个人理解】当一个服务出现异常、请求超时等,自动使用备份服务。

步骤

1、导入依赖

    <!--Hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.7.RELEASE</version>
    </dependency>

2、开启熔断机制

@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中!
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker//添加对熔断的支持 因为springboot 启动时不知道Hystrix
public class DeptProvider_hystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_hystrix_8001.class,args);
    }
    //增加一个Servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}

3、新增熔断备选方案

//提供Restful服务
@RestController
public class DeptController {
    @Autowired
    private DeptSerivce deptSerivce;

    @GetMapping("/dept/get/{id}")
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public Dept get(@PathVariable("id") long id) {
        Dept dept = deptSerivce.queryByid(id);
        if (dept == null) {
            throw new RuntimeException("id=>" + id + ",不存在改用户,或者信息找不到");
        }
        return dept;
    }

    //备选方案
    public Dept hystrixGet(@PathVariable("id") long id) {
        return new Dept()
                .setDepton(id)
                .setDname("id=>" + id + ",不存在改用户,或者信息找不到,null---@Hystrix")
                .setDb_source("no this database in MySQL");
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return deptSerivce.queryAll();
    }
}
服务降级

它是设置在客户端

服务被关闭,还能提示关闭的原因信息。

个人理解】当一个网站被关闭之后,服务不能再调用,在客户端我们可以准备一个后背工厂(FallbackFactory),返回一个缺省值,整体的服务水平降低了,但至少用户能够获得一个提示信息,能够访问者链接,比直接挂掉强。

】什么是服务降级?当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。

如果还是不理解,那么可以举个例子:假如目前有很多人想要给我付钱,但我的服务器除了正在运行支付的服务之外,还有一些其它的服务在运行,比如搜索、定时任务和详情等等。然而这些不重要的服务就占用了JVM的不少内存与CPU资源,为了能把钱都收下来(钱才是目标),我设计了一个动态开关,把这些不重要的服务直接在最外层拒掉,这样处理后的后端处理收钱的服务就有更多的资源来收钱了(收钱速度更快了),这就是一个简单的服务降级的使用场景。

第一种方式: 服务被关闭连接

步骤

1、导入依赖 ,Feign自带 Hystrix 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

2、创建一个Service类,就用之前的Ribbon的那个

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptServiceFallbackFactory.class)
 public interface DeptClientSerivce {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") long id);
    @GetMapping("/dept/list")
    public List queryAll();
    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

}

3、创建一个备用工厂实现服务降级,因为是返回的是一个Service类,所以叫工厂

//服务降级
@Component
public class DeptServiceFallbackFactory implements FallbackFactory {
    @Override
    public DeptClientSerivce create(Throwable throwable) {
        return new DeptClientSerivce() {
            @Override
            public Dept queryById(long id) {
                return new Dept()
                        .setDname("用户"+id+"改服务已被暂时关闭,暂被另一个服务使用资源")
                        .setDb_source("")
                        .setDepton(id);
            }
            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public boolean addDept(Dept dept) {
                return false;
            }
        };
    }
}

第二种方式: 访问超时或报错则提示用户

1、导入依赖

   <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        <version>2.2.0.RELEASE</version>
    </dependency>

2、编写配置

#开启降级feign.hystrixy
feign:
  hystrix:
    enabled: true

3、超时配置

如果我们使用的是@HystrixCommand注解,那么可以在注解中直接指定超时时间,如下:

@HystrixCommand(fallbackMethod="fallback",
    commandProperties = {
         @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000" )
    }
)

当然也可以指定commandKey,然后在配置文件中配置超时时间,如下:

@HystrixCommand(fallbackMethod="fallback",commandKey="userGetKey")

配置文件给commandKey配置超时时间:

hystrix.command.userGetKey.execution.isolation.thread.timeoutInMilliseconds = 13000

全局配置

如果想全局的配置,可以配置默认的超时时间:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000

4、使用注解

    @RequestMapping("/consumer/dept/list")
    @ResponseBody
    @HystrixCommand(fallbackMethod = "list_TimeOutHandler",commandProperties = {
            //超过3秒就调用提示方法
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000" )
    })
    public List<Dept> list(){
        try {
            TimeUnit.SECONDS.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int i = 10/0;
        return deptClientSerivce.queryAll();
    }
        //提示方法
    public List<Dept> list_TimeOutHandler(){
        Dept dept = new Dept();
        dept.setDname("系统繁忙或程序报错");
        List<Dept> list = Arrays.asList(dept);
        return list;
    }
流监控

个人理解】 可以对一个服务的流量进行监控,可以看见服务是否正常。

步骤

1、导入依赖

<!--Hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
 <!--流监控-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

2、编写配置

server:
  port: 9001

3、开启监控

@SpringBootApplication
@EnableHystrixDashboard //开启
public class DeptConsumerDashBoard_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashBoard_9001.class,args);
    }
}

【注】:启动这个服务,访问9001这个端口会调转到监控页面

Zuul

个人理解

微服务之间最好是没有互相联系,可以使用ReabbitMQ

Zuul是用于提供者服务端的反向代理,Fegin是作用在消费者客户端的,Fegin用于服务与服务的调用。

如果需要把服务的一些接口不经过消费者客户端把访问服务的访问路径暴露给前端,那就需要用Zuul来对请求过滤。

最主要的功能 路由 和 拦截

路由就是把服务的真实路径不暴露给外面,封装了原有路径,使得原有路径变成其他路径,且访问效果一样。

正向代理 隐藏客户端的真实地址

反向代理 隐藏服务端的真实地址

】Zuul是Spring Cloud全家桶中的微服务API网关。

所有从设备或网站来的请求都会经过Zuul到达后端的Netflix应用程序。作为一个边界性质的应用程序,Zuul提供了动态路由、监控、弹性负载和安全功能。Zuul底层利用各种filter实现如下功能:

  • 认证和安全 识别每个需要认证的资源,拒绝不符合要求的请求。
  • 性能监测 在服务边界追踪并统计数据,提供精确的生产视图。
  • 动态路由 根据需要将请求动态路由到后端集群。
  • 压力测试 逐渐增加对集群的流量以了解其性能。
  • 负载卸载 预先为每种类型的请求分配容量,当请求超过容量时自动丢弃。
  • 静态资源处理 直接在边界返回某些响应。

【步骤】

1、导入依赖

<!--zull-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

2、编写配置,需要把Zuul注册到注册中心

server:
  port: 9527

spring:
  application:
    name: springcloud-zuul
#ribbon:
#  ReadTimeout: 12000
#  ConnectTimeout: 12000
#  eureka:
#    enabled: true

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: zuul9527.com
    prefer-ip-address: true

info:
  app.name: li-springcloud
  company.name: lzhbk.cn

ribbon:
  eureka:
    enabled: true

zuul:
  routes:
  #绑定服务的ID,注意是小写,大写好像会有问题,一个Zuul只能绑定一个服务
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/**
  ignored-services: "*" #不能使用这个路径访问,忽略路径 '*'为隐藏全部服务
  prefix: /li #设置一个访问前缀

3、开启Zuul

@SpringBootApplication
@EnableZuulProxy //启动Zuul代理
public class ZuulApplication_9527 {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class,args);
    }
}

【总结】之后就算不通过服务端服务,也只能从Zuul设置的 /li 路径服务了,其他路径都会被拦截。

远程使用Config配置

个人理解】不用修改项目代码直接在GitHub上修改配置文件即可,方便运维人员维护。

步骤

1、先再GitHup上传一个配置文件

我的已经上传好了:https://gitee.com/liyitian/springcloud-config.git

2、创建一个服务端项目,导入Config服务端依赖

<!--config-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>

3、编写配置

server:
  port: 3344

spring:
  application:
    name: springcloud-config-server
    #连接远程仓库
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/liyitian/springcloud-config.git  # https ,不是git

4、在8001服务,导入依赖config

   <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>

5、修改8001服务配置文件,创建 bootstrap.yml 文件 和 application.yml文件

bootstrap.yml 文件 :

为什么要用boostrap?因为它是系统级别的配置,不会与远程配置文件冲突

#bootstrap.yml 是系统级别的配置
spring:
  cloud:
    config:
      name: config-client #需要从git上读取的资源名称,不需要后缀
      profile: test #拿到dev生产环境
      label: master
      uri: http://localhost:3344

application.yml文件:

spring:
  application:
    name: springcloud-config-dept-8001

总结

我们会发现,Spring Cloud Ntiflix 很简单,总共也就四个步骤

1、导入依赖

2、编写配置

3、开启服务

4、运行项目

其中主要是理论知识多,我们可以通过自己的理解去简化这些理论知识。