IT必备技能springcloud分布式服务

springCloud --- 高级篇(1)

2020-06-07  本文已影响0人  贪挽懒月

本系列笔记涉及到的代码在GitHub上,地址:https://github.com/zsllsz/cloud

本文涉及知识点:

一、springCloud Alibaba简介

1、为什么会诞生springCloud Alibaba?
通过springCloud初级篇和中级篇的学习,我们知道springCloud很多技术现在都停更了,Netflix也说明了不再维护了。一开始阿里搞出了一个Dubbo,但是后面停更了几年,spring就联合Netflix搞出了一个springCloud生态,Netflix主要技术有5个,eureka、ribbon、feign、zuul和config。但是呢Netflix内部神仙打架,意见不一,然后导致这些技术大部分停更了。这时,阿里又杀出来了,搞出了一套springCloud Alibaba,spring官方看它还不错,阿里也想推广自己,所以在2018年四月份spring又把springCloud Alibaba给收编了。所以对于我们使用者而言,无非就是从 springCloud Netflix 换成 springCloud Alibaba而已。

2、springCloud Alibaba能干嘛?

可以发现,springCloud能干的它几乎都能干,还多了一些springCloud不能干的。springCloud Alibaba相关网址如下,可以查阅相关文档:
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html
一般我们要学怎么使用查第二个文档就好了。

二、springCloud Alibaba Nacos 代替eureka做服务注册中心

之前springCloud的服务注册可以用eureka、consul和zookeeper,配置中心用config和bus,现在springCloud Alibaba用Nacos搞定这些,简言之就是注册中心加配置中心。
1、下载安装:

bash startup.sh -m standalone

2、基于nacos的服务提供者:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<!-- nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
server:
  port: 9001
spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.0.106:8848
# 端点启动和暴露(这时actuator的功能,学springcloud config时也配置过)
management:
  endpoints:
    web:
      exposure:
        include:
        - "*"
@SpringBootApplication
@EnableDiscoveryClient
public class NacosMainPayment9001 {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(NacosMainPayment9001.class, args);
    }
}
@RestController
@RequestMapping("/provider")
public class PaymentController {
    
    @GetMapping("/payment/{id}")
    public String payment(@PathVariable("id") Integer id) {
        return "success" + id;
    }
}

3、基于nacos的服务消费者:

server:
  port: 80
spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.0.106:8848
# 消费者将要去访问的微服务名称
service-url:
  nacos-user-service: http://nacos-payment-provider
@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
@RestController
@RequestMapping("/consumer")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;
    
    @Value("${service-url.nacos-user-service}")
    private String serverUrl;
    
    @GetMapping("/order/{id}")
    public String getPayment(@PathVariable("id") Integer id) {
        return restTemplate.getForObject(serverUrl + "/provider/payment/" + id, String.class);
    }
}

访问这个controller,就会发现一次是调用9001,一次是调用9002。因为nacos也集成了ribbon,所以自带负载均衡。

4、nacos的CAP模型:
nacos支持CP和AP,可以自由切换。这样一来,nacos可以代替所有的注册中心。如果要代替eureka,用AP,如果要代替consul或者zookeeper,用CP。

三、springCloud Alibaba Nacos 代替config做服务配置中心

1、新建名为cloudalibaba-config-nacos-client3377的module:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<!-- nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- nacos config -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
server:
  port: 3377
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.0.106:8848
      config:
        server-addr: 192.168.0.106:8848
        file-extension: yaml #指定yaml格式的配置,就是对应以前用config时GitHub上的配置文件

application.yml:

spring:
  profiles:
    active:
    - dev #激活开发环境
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigMain3377 {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(NacosConfigMain3377.class, args);
    }
}
@RestController
@RequestMapping("/config")
@RefreshScope // 动态刷新
public class NacosConfigController {
    @Value("${config.info}")
    private String info;
    
    @GetMapping("/info")
    public String info() {
        return info;
    }
}

至此工程新建完毕,接下来就要去nacos中新建配置文件。

2、在nacos上新建配置文件:

nacos配置管理

可以看到有一个Data Id,一个Group。
Data Id的格式:

${prefix}-${spring.profile.active}.${file-extension}
新建配置

这个配置一定要注意每个冒号后面要加一个空格!

成功读取到配置

3、nacos配置管理的命名空间、data id和group的关系:

nacos

所以三者关系就是:namespace + group + data Id可以确认一个唯一的配置文件。

这样设计的好处就是可以方便地区分不同的环境。比如现在有开发、测试和生产三个环境,那我们就新建三个不同的namespace。

使用默认命名空间默认分组读取不同data id的配置文件:

使用默认命名空间不同分组读取配置配置文件:

server:
  port: 3377
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.0.106:8848
      config:
        server-addr: 192.168.0.106:8848
        file-extension: yaml #指定yaml格式的配置,就是对应以前用config时GitHub上的配置文件
        group: DEV_GROUP
spring:
  profiles:
    active:
    #- dev #激活开发环境
    - info

这样就搞定了,这样读取的就是dev_group分组下的info配置文件。

使用不同的命名空间读取不同的配置文件:

命名空间

bootstrap.yml再加一行配置,如下:

server:
  port: 3377
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.0.106:8848
      config:
        server-addr: 192.168.0.106:8848
        file-extension: yaml #指定yaml格式的配置,就是对应以前用config时GitHub上的配置文件
        namespace: 4d4b4c98-2746-4ff7-8ce9-eb2837db456c
        group: DEV_GROUP

这样就可以指定命名空间指定分组读取指定后缀文件了。

四、nacos集群和持久化

官网的集群架构图:VIP的意思是虚拟IP,我们可以认为vip就是nginx的集群。

nacos集群架构图

nacos默认自带了一个数据库(derby)用来做持久化,当nacos集群的时候,每一台服务器上的nacos都以自己自带的数据库来搞持久化,会存在数据一致性的问题。所以干脆都别用自带的数据库了,都用MySQL。

1、用MySQL做持久化:

spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://192.168.0.106:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=你的MySQL密码

2、nacos集群:
需要的环境:

nginx集群和mysql已经安装好了,nacos集群通过如下步骤搞定:

192.168.2.43:8848
192.168.2.43:8849
192.168.2.43:8850

由于这里是在一台虚拟机上启动3份nacos,所以后面要加上端口。如果有3台不同的机器,那么这里直接写那3台机器的ip就好了。并且要注意,这个ip不能填写127.0.0.1,执行hostname -i,填写ens33后面跟着的那个IP。

增加端口启动

第二次启动,启动日志增加端口打印,如下图,上面是修改前,下面是修改后:

增加端口打印

这样就改完了。

 upstream cluster {
      server  192.168.2.43:8848;
      server  192.168.2.43:8849;
      server  192.168.2.43:8850;
  }

  server {
      listen       80;
      server_name  192.168.2.43;
      location / {
      proxy_pass  http://cluster;
  }

这样所有配置都整完了,接下来依次启动nginx和nacos.

./startup.sh -p 8848
./startup.sh -p 8849
./startup.sh -p 8850

启动成功后,访问:192.168.2.43/nacos,登录后可以看到如下效果:

集群节点

可能遇到的坑:

unable to find local peer: 192.168.2.43:0, all peers: [192.168.2.43:8850, 192.168.2.43:8849, 192.168.2.43:8848]

解决办法:在nacos/config/application.properties中加上如下配置:

nacos.inetutils.ip-address=192.168.2.43
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

五、springCloud Alibaba Sentinel介绍和基本使用

1、sentinel介绍:
之前我们用hystrix豪猪哥来实现服务降级熔断,sentinel也是干这事的,并且更加强大和好用。

sentinel能够解决的问题:

2、优点:

3、下载安装:

sentinel

相比豪猪哥,简单了很多,豪猪哥需要我们引入依赖后自己启动一个微服务当成dashboard,而sentinel不需要自己写,直接运行jar包就可以了。

4、初用sentinel:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<!-- nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 做持久化的时候会用到的 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- sentinel -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- openfeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

application.yml:

server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.0.106:8848
    sentinel:
      transport:
        dashboard: 192.168.0.106:8080
        port: 8719 # 默认8719,如果被占用会依次加1,直至找到没有被占用的端口
# actuator图形化配置
management:
  endpoints:
    web:
      exposure:
        include:
        - "*"

主启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class SentinalMain8401 {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(SentinalMain8401.class, args);
    }
}

controller:

@RestController
@RequestMapping("/sentinel")
public class FlowLimitController {

    @GetMapping("/testA")
    public String testA() {
        return "=========== testA ==========";
    }
    
    @GetMapping("/testB")
    public String testB() {
        return "=========== testB ==========";
    }
}

8080控制台并没有任何8401的相关信息,不要方,这是因为sentinel使用懒加载机制,没调用的不会出现在dashboard中。访问一下8401,然后再看dashboard中就有了。

sentinel正在监控8401

然后访问几次8401,实时监控中就会有相关信息了,如下图:

testA的调用信息

可能遇到的坑:不管怎么访问8401,实时监控中都没有调用信息,可能的原因有:

yum -y install ntp ntpdate
ntpdate cn.pool.ntp.org
java.util.concurrent.ExecutionException: java.net.NoRouteToHostException: 没有到主机的路由

解决办法就是在8401的application.yml中加上如下配置:

sentinel:
      transport:
        dashboard: 192.168.0.106:8080
        client-ip: 192.168.0.104 # 这一行是新加的
        port: 8719 # 默认8719,如果被占用会依次加1,直至找到没有被占用的端口

就是加上client-ip,值就是8401项目,即你要sentinel监控的项目所运行的机器的IP。

六、sentinel流控规则

1、基本介绍:

sentinel流控规则

在sentinel的dashboard中有一个流控规则,如上图,下面对这些名词进行解释。

2、流控模式:

流控模式之直接:

QPS直接快速失败:

sentinel QPS直接快速失败

这里设置的意思就是,访问testB,一秒钟超过一次,就是直接快速报错。我现在对testB连点两下,就会返回如下信息:

sentinel对testB进行流控

线程数直接失败:

sentinel线程数直接失败

我们再访问testB,发现不管点多快,都没有被流控给拦住。因为我们在一个浏览器中访问,始终是一个线程。这样配置的意思就是并发线程数超过阈值1时,就会返回失败信息。可以用jmeter模拟并发访问的情况。

流控模式之关联:

配置如下:

sentinel流控之关联

这里的意思就是testA的QPS数超过1,就会导致testB不能用。测试方法:用jmeter对testA进行并发访问,然后我们在浏览器访问testB。就会发现也会返回Blocked by Sentinel (flow limiting)

流控模式之链路:
多个请求调用了同一个微服务超过了QPS阈值就会快速失败,配置如下:

sentinel流控之链路

注意入口资源的名字就是sentinel簇点链路中显示的名字。然后快速访问A,只要QPS超过1,就会返回Blocked by Sentinel (flow limiting)

3、流控效果:
上面用的流控效果都是快速失败,现在来认识一下这些流控效果。

sentinel流控效果之预热 sentinel流控效果之排队等待
上一篇下一篇

猜你喜欢

热点阅读