Spring Cloud Alibaba

Spring Cloud

Spring Cloud 这个微服务的框架其实就是Spring Boot将Netflix公司旗下产品结合在一起孕育而生的一个框架,Spring Cloud = Spring Boot + Netflix(Eureka;Ribbon;Hystrix;Zuul;Config),在这个过程中Spring Boot其实也没干啥大事儿,就是将两套产品捆在一起稍作封装就形成Spring Cloud,学习Spring Cloud其实就是学习Netflix的五大组件。

Spring Cloud解决的不是在生产过程的某一个问题,它解决的是服务之间相互调用的问题,比如:

  • 当某个项目的服务地址、端口一旦发生改变,那么其它调用该服务的项目,都需要修改调用地址,服务和服务之间入侵太大,耦合度太高。

Spring Cloud Alibaba

很多人可能会问,有了 spring cloud 这个微服务的框架,为什么又要使用 spring cloud alibaba 这个框架了?最重要的原因在于spring cloud中的几乎所有的组件都使用 Netflix 公司的产品,然后在其基础上做了一层封装。然而Netflix的服务发现组件Eureka已经停止更新,我们公司在使用的时候就发现过其一个细小的Bug;而其他的众多组件预计会在明年(即2020年)停止维护。所以急需其他的一些替代产品,也就是 spring cloud alibaba,目前正处于蓬勃发展的态式。

微服务:就是业务能力来拆分为一个个工程,每个工程是以一种去中心化的方式来独立运行和部署。
拆分方式:以数据为维度进行拆分、基于业务功能拆分、基于团队拆分、基于业务边界拆分

注册中心Nacos

在这里插入图片描述

nacos的作用就是实现了服务间调用的解耦,可以方便的水平扩展。nacos是阿里巴巴研发的一个集注册中心与配置中心于一体的管理平台,使用其他非常的简单。下载地址:https://github.com/alibaba/nacos/releases
第一步:下载:

版本:NACOS2.1.0:https://github.com/alibaba/nacos/releases/download/2.1.0/nacos-server-2.1.0.tar.gz
版本:NACOS2.1.1:

第二步:将下载好的tar包通过xftp放入/data/nacos目录下,并解压

cd /data/nacos
tar -zxvf nacos-server-2.1.0.tar.gz 

第三步:配置数据库

cd /data/nacos/nacos/conf
vim application.properties
## 找到如下相关的配置进行修改:
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2

第三步:添加数据库:

## 切换到conf目录下,找到nacos-mysql.sql,在navicate中执行该文件
cd /data/nacos/nacos/conf
## 找到nacos-mysql.sql,在navicate中执行该文件

第四步:开放端口

## 开放默认端口
firewall-cmd --zone=public --add-port=8848/tcp --permanent
## 这俩端口不开放的话SpringBoot项目启动之后会报错Request nacos server failed:
firewall-cmd --zone=public --add-port=9848/tcp --permanent
firewall-cmd --zone=public --add-port=9849/tcp --permanent

在这里插入图片描述
第五步:启动Nacos

cd /data/nacos/nacos/bin
sh startup.sh -m standalone

网页访问地址:http:ip:8848/nacos
默认的登录名和密码是:nacos/nacos

Spring Boot整合Nacos

第一步:导入依赖,注意:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>com.alibaba.cloud</groupId>
           <artifactId>spring-cloud-alibaba-dependencies</artifactId>
           <version>2.2.9.RELEASE</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-dependencies</artifactId>
           <version>Hoxton.SR12</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
   </dependencies>
</dependencyManagement>

第二步:配置yml

spring:
  application:
  	# 服务名
    name: spring-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.119.134:8848
        # 将自己注册到注册中心
        register-enabled: true

第三步:调用

package com.example.demo.config.restTemplateConfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

package com.example.demo.nacos;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.client.RestTemplate;

import java.util.List;

public class FirstNacos {
    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    private RestTemplate restTemplate;

    private void useNacos(){
        List<ServiceInstance> instances = discoveryClient.getInstances("service-name");
        String url = instances.stream().map(ele -> {
            return "http://" + ele.getHost() + ":" + ele.getPort() + "/url";
        }).findFirst().get();
        String result = restTemplate.getForObject(url, String.class);
    }
}

Ribbon负载均衡

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。其主要功能是提供客户端的负载均衡算法,并提供了完善的配置项如连接超时,重试等。简单的说,就是配置文件中列出Load Balancer后面所有的机器,Ribbon会自动的基于某种规则(如简单轮询,随机连接等)去连接这些机器,当然我们也可以使用Ribbon自定义负载均衡算法。

在单节点服务模式下,采取上述方式调用服务未尝不可,但是在集群服务模式下,我们就需要自己手动通过一定的策略实现服务调用的负载均衡,Ribbon通过在restTemplate添加@LoadBalanced注解即可实现服务调用的负载均衡,Ribbon的出现是为了解决服务集群模式下服务调用负载均衡的问题。

Ribbon只是一个客户端的负载均衡器工具,实现起来非常的简单,我们只需要在注入RestTemplate的bean上加上@LoadBalanced就可以了。如下:

package com.example.demo.config.restTemplateConfig;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    //通过Ribbon实现服务调用的负载均衡
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
package com.example.demo.nacos;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;

import java.util.List;

public class RibbonNacos {
    @Autowired
    private RestTemplate restTemplate;

    public void userRibbonOne(){
        List<String> result = restTemplate.getForObject("http://service-name/url1", List.class);
    }

    public void userRibbonTwo(){
        List<String> result = restTemplate.getForObject("http://service-name/url2", List.class);
    }

    public void userRibbonThree(){
        List<String> result = restTemplate.getForObject("http://service-name/url2", List.class);
    }

    public void userRibbonFoue(){
        List<String> result = restTemplate.getForObject("http://service-name/url4", List.class);
    }
}

Ribbon提供了一个很重要的接口叫做IRule,其中定义了很多的负载均衡策略,默认的是轮询的方式,以下是Ribbon的负载均衡策略:

类名描述
RoundRobbinRule轮询
RandomRule随机挑选
RetryRule按照轮询的方式去调用服务,如果其中某个服务不可用,但是还是会尝试几次,如果尝试过几次都没有成功,那么就不在调用该服务,会轮询调用其他的可用服务。
AvailabilityFilteringRule会先过滤掉因为多次访问不可达和并发超过阈值的服务,然后轮询调用其他的服务
WeightedResponseTimeRule根据平均响应时间计算权重,响应越快权重越大,越容易被选中。服务刚重启的时候,还未统计出权重会按照轮询的方式;当统计信息足够的时候,就会按照权重信息访问
ZoneAvoidanceRule判断server所在的区域性能和可用性选择服务器
BestAvailableRule会过滤掉多次访问都不可达的服务,然后选择并发量最小的服务进行调用,默认方式
改变Ribbon的负载均衡策略

只需要在Spring的IOC容器中注入对应的策略的Bean就可以了

@Bean
public IRule getRule() {
    return new RandomRule();
}
自定义负载均衡策略

第一步:自定义的负载均衡策略需要继承AbstractLoadBalancerRule这个类,然后重写choose方法

public class Customize_Rule extends AbstractLoadBalancerRule {

    private static Logger logger = LoggerFactory.getLogger(Customize_Rule.class);

    private int currentIndex = 0; //当前调用的索引
    private int num = 1; //次数
    private int limit = 5;

    /**
     * 初始化工作
     * @param iClientConfig
     */
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

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

    private Server choose(ILoadBalancer balancer, Object key) {
        Server server = null;

        while(null == server) {
            //获取所有可用的服务
            List<Server> reachableServers = balancer.getReachableServers();
            if (0 == reachableServers.size()) {
                logger.error("没有可用的服务");
                return null;  //退出while循环
            }

            int total = reachableServers.size(); //可用服务的数量

            synchronized (this) {
                /**
                 * 有种极端情况,当我们在使用最后一个服务的时候,其他的服务都不可用,可能导致索引越界异常
                 */
                if (currentIndex + 1 > total) {
                    currentIndex = 0;
                    server = reachableServers.get(currentIndex);  //获取第一个服务
                    num = 0;
                    num++;
                } else {
                    if(limit == num) {
                        currentIndex++;
                        num = 0;
                        if(currentIndex == total) {
                            currentIndex=0;
                            server = reachableServers.get(currentIndex);  //获取第一个服务
                            num++;
                        }else{
                            server = reachableServers.get(currentIndex);
                            num++;
                        }
                    }else {
                        server = reachableServers.get(currentIndex);
                        num++;
                    }
                }
            }
        }
        return server;
    }
}

第二步:将自定义的负载均衡策略注入到容器中

@Bean
public IRule getRule() {
    return new Customize_Rule();
}

Feign负载均衡

通过上面代码不难看出,采用restTemplate.getForObject(“http://service-name/url4”, List.class)的方式造成了大量代码重复,Feign的出现是为了解决Ribbon通过RestTemplate调用服务时大量代码重复的问题,通过Feign调用远程服务就像调用本地方法一样。

feign是基于Ribbon的另外一个负载均衡的客户端框架,只需要在接口上定义要调用的服务名即可,使用起来非常的简单:

第一步:导入依赖

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

第二步:在启动类上添加@EnableFeignClients

package com.example.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class Demo2Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo2Application.class, args);
    }

}

第三步:添加一个Service,该Service…

在这里插入代码片

Sentinel流量防卫兵

分布式系统中一个微服务需要依赖于很多的其他的服务,那么服务就会不可避免的失败。例如A服务依赖于B、C、D等很多的服务,当B服务不可用的时候,会一直阻塞或者异常,更不会去调用C服务和D服务。同时假设有其他的服务也依赖于B服务,也会碰到同样的问题,这就及有可能导致雪崩效应。
在这里插入图片描述
Sentinel是一个用于分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖会不可避免的调用失败,例如超时,异常等,Sentinel能保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

@SentinelResource(value = “” , blockHandler = “”)注解
@FeignClient(value = “serverName” , fallBackFactory = FallBackFactory.class)
@ControllerAdvice 和 ResponseBodyAdvice
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值