SpringCloudAlibaba

Nacos

一、下载安装

1、下载

linux:https://github.com/alibaba/nacos/releases/download/2.0.4/nacos-server-2.0.4.tar.gz

执行下载命令
wget https://github.com/alibaba/nacos/releases/download/2.0.4/nacos-server-2.0.4.tar.gz
解压安装包
tar -zxxvf nacos-server-2.0.4.tar.gz nacos/

2、linux部署

(1)创建数据库nacos,执行conf目录下的nacos-mysql.sql脚本,初始化数据库

(2)进入conf目录编辑application.properties

(4)在bin目录下启动

./startup.sh -m standalone   //standalone代表着单机模式运行,非集群模式

看到最后一行的successfully启动成功 

(5)将nacos配置为系统服务

①添加文件nacos.service    vim /lib/systemd/system/nacos.service     并且增加如下信息 (nacos路径替换成自己的路径即可)

[Unit]
Description=nacos
After=network.target
 
[Service]
Type=forking
ExecStart=/usr/nacos-server-1.1.3/nacos/bin/startup.sh -m standalone
ExecReload=/usr/nacos-server-1.1.3/nacos/bin/shutdown.sh
ExecStop=/usr/nacos-server-1.1.3/nacos/bin/shutdown.sh
PrivateTmp=true
 
[Install]
WantedBy=multi-user.target

②编辑nacos/bin目录下的startup.sh, 修改JAVA_HOME的路径,注释其他三项

③执行以下命令

1. 重新加载所有service服务
systemctl daemon-reload
2. 开机启动nacos.service
systemctl enable nacos.service
3. 查看该service是否开机启用
systemctl is-enabled nacos.service
4. 启动该服务
systemctl start nacos.service
可能报错: Job for nacos.service failed because the control process exited with error code. See "systemctl status nacos.service" and "journalctl -xe" for details.
5. 查看该服务状态
systemctl status nacos.service

3、访问nacos:http://localhost:8848/nacos

初始账号密码:nacos/nacos.

二、nacos注册中心

1、依赖导入

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

2、服务注册 

spring: 
    application: 
        name: sca-provider #服务注册的服务名 ,注意服务名的横线
    cloud: 
        nacos: 
            discovery: 
                server-addr: localhost:8848 #向nacos控制台注册

3、启动该工程查看是否注册成功

客户端定时(5秒)向nacos发送请求(心跳包),中断15秒,nacos客户端显示不健康,30秒认为中断死亡

 

三、服务远端调用

1、restTemplate远端调用

什么是restTemplate:传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient。不过此种方法使用起来太过繁琐。spring提供了一种简单便捷的模板类来进行操作,这就是RestTemplate。

在SpringCloud的项目中,我们使用了自动配置的OAuth2RestTemplate,RestTemplate,但是在使用这些restTemplate的时候,url必须是服务的名称,如果要调用真实的域名或者ip的url,会有错误

@Bean 
public RestTemplate restTemplate(){ //基于此对象实现远端服务调用  
    return new RestTemplate(); 
}
restTemplate实现远端调用,此方法是将该类交给spring管理
@Autowired
private RestTemplate restTemplate;  // 实现远端调用服务

restTemplate.getForObject(url, String.class);//参数一调用远端的url,参数二为该方法返回值类型的class对象

2、loadBalancerClient远端调用负载均衡客户端

LoadBalancerClient: 是 SpringCloud 提供的一种负载均衡客户端,Ribbon 负载均衡组件内部也是集成了 LoadBalancerClient 来实现负载均衡。

@Autowired
private LoadBalancerClient loadBalancerClient; //此对象负责从nacos服务中发现和获取服务实例

         //  /ˈbælənsə(r)/ /ˈklaɪənt/
@GetMapping("/controller/doRestEcho02")
public String doRestEcho02() {
    ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
    String url = String.format("http://%s:%s/provider/echo/%s", 
                               serviceInstance.getHost(),         
                               serviceInstance.getPort(), appName);  
                               //从nacos获取provider服务注册信息

    System.out.println("url  :" + url);
    return restTemplate.getForObject(url, String.class);
}

3、loadBalancer注解简化服务获取过程

在restTemplate交给spring管理的方法上加上@loadBalancer在该步骤请求发送时,底层对该请求拦截,然后底层执行choose等一系列方法,获取host和port进行请求拼接

@Autowired
private RestTemplate loadBalancedRestTemplate;

@GetMapping("/controller/doRestEcho03")
public String oRestEcho03() {
    String serviceId = "sca-provider";
    String url = String.format("http://%s/provider/echo/%s", serviceId, appName);
    return loadBalancedRestTemplate.getForObject(url, String.class);//在该步骤请求发送时,底层对该请求拦截,
                                                                    // 然后执行方法二的choose等一系列方法,获取host和port进行请求拼接

}

4、OpenFeign实现远程服务调用,实现代码结构的优化

什么是OpenFeign

OpenFeign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)(称OpenFeign作用:声明式服务调用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求。学习完OpenFeign后可以不使用RestTemplate进行调用。

  • OpenFeign是Spring Cloud的子项目,而Feign是Netflix公司研发的;
  • Feign不支持SpringMVC的注解,另外Feign已不再维护,OpenFeign正常维护;

(1)添加依赖

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

(2)在启动类上添加@EnableFeignClients,作用类似于@MapperScan

(3)service层创建接口

@Autowired
private RemoteProviderService remoteProviderService;

@GetMapping("/controller/doFeignEcho/{msg}")
public String doFeignEcho(@PathVariable String msg) {
    return remoteProviderService.echoMassage(msg);
}

5、Ribbon负载均衡策略

  • Ribbon是Netflix开源的负载均衡组件,可以用来做客户端负载均衡,调用注册中心的服务;
  • OpenFeign与Feign都内置了Ribbon,用于实现负载均衡;

Nacos中的负载均衡底层是通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务

随机策略  轮询策略  重试策略  最低并发策略  可用过滤策略  响应时间加权重策略  区域权重策略

四、Nacos服务配置中心

配置中心的作用动态管理发布配置,无需重启服务配置经常变化的配置信息,例如连接池,日志、线程池、限流熔断规则等。

(1)添加服务配置依赖

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

(2)将项目application.yml的名字修改为bootstrap.yml(启动优先级最高),并添加配置中心配置

cloud:
     nacos:
       discovery:    #配置服务注册中心地址
          server-addr: 127.0.0.1:8848  
       config:       #配置服务配置中心地址
         server-addr: 127.0.0.1:8848
         file-extension: yml

五、Nacos配置管理模型

1、Namespace:命名空间

Nacos中的命名空间一般用于配置隔离,这种命名空间的定义一般会按照环 境(开发,生 产等环境)进行设计和实现.我们默认创建的配置都存储到了 public命名空间

更换命名空间:

在xml文件config下新增namespace: 命名空间的id

2、Group:分组

当我们在指定命名空间下,按环境或服务做好了配置以后,有时还需要基于 服务做分组配置, 例如,一个服务在不同时间节点(节假日,活动等)切换 不同的配置

更换分组:

在xml文件config下新增group: 分组名称

3、Service/DataId:共享配置

在xml文件config下新增    

 shared-configs[0]:    #该命名空间下共享配置的引用,共享配置不止一个,使用下标依次引用。

   data-id: app-public.yml  #该命名空间下共享配置的 Data id的值

   refresh: true   #支持配置中心共享配置改变,动态刷新该共享配置。 默认fales

   #group: DEFAULT_GROUP  #该命名空间下分组名称。#DEFAULT_GROUP,作为共享配置,创建时默认分组                                                                                                                            
                            名。                    

4、具体配置

 六、实时nacos中的配置参数

写一个Controller试试看,这里代码中需要加上 @RefreshScope 注解,注解作用就是当nacos中的配置文件更新的时候,同步更新到代码中! 

@RestController
@RequestMapping("/TestController")
@RefreshScope
public class TestController {

    @Value("${pattern.envSharedValue}")
    private String myName;

    @GetMapping("/test1")
    public String test1() {
        return myName;
    }
}

Sentinel

作用:分布式系统的流量防卫兵

下载网址:https://github.com/alibaba/Sentinel/releases

知识补充:限流算法

计数器、令牌桶、漏斗算法,滑动窗口算法

Sentinel 默认的限流算法是滑动窗口算法

一、Sentinel环境搭建

 (1)添加依赖

<dependency> 

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> 

</dependency>

(2)配置bootstrap.yml

spring:
  cloud:
    sentinel: 
      transport:
        dashboard: localhost:8180 # 指定sentinel控制台地址。

(3)找到目录执行运行命令

java-Dserver.port=8180-Dcsp.sentinel.dashboard.server=localhost:8180-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar

idea启动Sentinel

-Dserver.port=8180

-Dcsp.sentinel.dashboard.server=localhost:8180

-Dproject.name=sentinel-dashboard

-jar

D:\javaXM\sentinel-1.8.1\sentinel-dashboard-1.8.1.jar

二、Sentinel限流

QPS(代表每秒请求次数)单机阈值设置请求次数为1,代表每秒请求不超1次,超过做限流处理,处理方式直接调用失败。

流控模式:

直接,关联和链路

Sentinel的限流效果快速失败,预热,排队等待

链路模式实例:

  /**
@SentinelResource使用此注解描述的方法,在此方法被访问时,会sentinel的簇点链路中显示,此注解中指定的

名字就是资源名。此注解中的blockHandlerClass用于指定,出现限流异常时的异常处理类,blockHandler属性

用于指定异常处理类中的方法(此方法的返回类型,参数要与 @SentinelResource注解描述的方法参数一致,可

以BlockException异常类型参数,而且方法必须是静态.)fallbackClass 用于指定业务异常处理类,fallback

用于指向业务处理类中的异常处理方法(此方法的返回类型,参数要与@SentinelResource注解描述的方法参

数一致,可以加Throwable异常类型参数)

   */

@SentinelResource(value="doGetResource",
                  blockHandlerClass = ResourceBlockHandler.class,

                  blockHandler = "call",

                  fallback = "call",

                  fallbackClass = ResourceFallbackHandler.class)

    public String doGetResource(){

        return "do get resource";

    }

说明:流控模式为链路模式时,Sentinel Web过滤器默认聚合所有URL的入口为sentinel_spring_web_context,在application.yml添加如下语句来关闭URL PATH聚合,入口名就不为默认

sentinel:

     web-context-unify: false

三、Sentinel熔断降级

作用:对调用链路中不稳定的资源进行熔断降级

熔断策略:

慢调用比例:请求数超过3时,平均响应时间超过200毫秒的有30%,则对请求进行熔断,熔断时长为10秒钟,10秒以后恢复正常。

②异常比例   

③异常数

四、Sentinel 异常处理

系统提供了默认的异常处理机制,如默认处理机制不满足我们需求,我们可以自己进行定义

实现方式:定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理。

@Slf4j

@Component

public class ServiceBlockExceptionHandler implements BlockExceptionHandler {

    @Override

    public void handle(HttpServletRequest request,

                       HttpServletResponse response,

                       BlockException e) throws Exception {

        //设置响应数据编码

        response.setCharacterEncoding("utf-8");

        //告诉客户端响应数据的类型,以及客户端显示内容的编码

        response.setContentType("text/html;charset=utf-8");

        //向客户端响应一个json格式的字符串

        //String str="{\"status\":429,\"message\":\"访问太频繁了\"}";

        Map<String,Object> map=new HashMap<>();

        map.put("status", 429);

        map.put("message","访问太频繁了");

//将map集合变为json格式的字符串

        String jsonStr=new ObjectMapper().writeValueAsString(map);

        PrintWriter out = response.getWriter();

        out.print(jsonStr);

        out.flush();

        out.close();

    }

}

 五、Sentinel 热点规则 

作用:对经常使用的数据做配置

①写方法

@GetMapping("/sentinel/findById")

        @SentinelResource("resource")

        public String doFindById(@RequestParam("id") Integer id){

            return "resource id is "+id;

        }

②设置限流的热点

资源名:@SentinelResource注解的值

参数索引@SentinelResource注解的方法参数下标,0代表第一个参数,1代表第二个参数。

单机阈值以及统计窗口时长表示在此窗口时间超过阈值就限流。

参数例外项:表示参数为5时阈值为100,其它参数值阈值为1.

六、Sentinel 系统规则

作用:监控服务器的状态,保证服务器正常的运行

Sentinel的常用系统规则

RT,QPS,CPU,线程,Load-linux,unix

七、Sentinel授权规则

作用:根据黑白名单规则,限制请求是否通过,只有请求来源位于不在黑名单或则在白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过

基于参数授权规则的实现

定义请求解析器

        用于对请求进行解析(RequestOriginParser接口的实现类),并返回解析结果,sentinel底层在

        拦截到用户请求以后,会对请求数据基于此对象进行解析,判定是否符合黑白名单规则

@Component

public class DefaultRequestOriginParser implements RequestOriginParser {

    @Override

    public String parseOrigin(HttpServletRequest request) {

        String origin = request.getParameter("origin");//这里的参数名会与请求中的参数名一致

        return origin;

    }

}

定义流控规则

资源名:即限流规则的作用对象

流控应用:对应的黑名单/白名单中设置的规则值,多个值用逗号隔开.

执行资源访问

基于请求ip等方式进行黑白名单的规则设计

定义请求解析器

@Component

public class DefaultRequestOriginParser  implements RequestOriginParser {

    //解析请求源数据

    @Override

    public String parseOrigin(HttpServletRequest request) {

        //获取访问请求中的ip地址,基于ip地址进行黑白名单设计(例如在流控应用栏写ip地址)

        String ip= request.getRemoteAddr();

        System.out.println("ip="+ip);

        return ip;

    }//授权规则中的黑白名单的值,来自此方法的返回值

}

定义流控规则

Gateway网关

作用:一个各种服务访问的入口在项目中简化前端的调用逻辑,同时也简化内部服务之间互相调用的复杂度

特点:

(1)性能强劲:是第一代网关Zuul的1.6倍。

(2)依赖Netty与WebFlux(Spring5.0),不是传统的Servlet编程模型 (Spring MVC就是基于此模型实现),学习成本高。

(3)需要Spring Boot 2.0及以上的版本,才支持

一、配置流程

(1)导入依赖:

<dependency>
     <groupId>org.springframework.cloud</groupId>

     <artifactId>spring-cloud-starter-gateway</artifactI
</dependency>

(2)application.yml(假如已有则无须创建)添加相关配置设定uri实现负载均衡

gateway:  #和nacos同一级

    routes: #配置网关路由规则

      - id: route01  #路由id,自己指定一个唯一值即可

           uri: lb://sca-provider

          #uri: http://localhost:8082/ #网关帮我们转发的url(url是uri  的子集,uri是统一资源标 
                                         识符)

           predicates: #断言(谓此):匹配请求规则

             - Path=/nacos/provider/echo/** 

             - Before=2021-01-30T00:00:00.000+08:00 

             - Method=GET

          #请求路径定义,此路径对应uri中的资源,**代表传入的参数

          filters: #网关过滤器,用于对谓词中的内容进行判断分析以及处理

             - StripPrefix=1 #转发之前去掉path中第一层路径

Predicate(断言)又称谓词,用于条件判断,只有断言结果都为真,才会真正的执行路由

二、断言的类型

(1)基于Datetime类型的断言工厂,此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory:判断请求日期是否晚于指定日 期

BeforeRoutePredicateFactory:判断请求日期是否早于指定 日期

BetweenRoutePredicateFactory:判断请求日期是否在指定 时间段内

例:-After=2020-12-31T23:59:59.789+08:00[Asia/Shanghai]:判断请求日期是否晚于指定日期

(2)基于header的断言工厂HeaderRoutePredicateFactory,判断请求Header是否具有给定名称且值与正则表达式匹配

例:-Header=X-Request-Id, \d+

(3)基于Method请求方法的断言工厂,MethodRoutePredicateFactory

接收一个参数,判断请求类型是否跟指定的类型匹配

例:-Method=GET

(4)基于Query请求参数的断言工厂,QueryRoutePredicateFactory 

接收两个参数,请求param和正则表达式, 判断请求参数是否具 有给定名称且值与正则表达式匹配.

例:-Query=pageSize,\d+

三、网关限流

(1)添加依赖

<dependency>

   <groupId>com.alibaba.cloud</groupId>

   <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>

</dependency>



<dependency>

   <groupId>com.alibaba.cloud</groupId>

   <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>

</dependency>

(2)添加Sentinel 控制台地址

sentinel: 

    transport: 

        dashboard: localhost:8180 #Sentinel 控制台地址 

    eager: true #取消Sentinel控制台懒加载,即项目启动即连接

(3)添加sentinel的jvm参数,通过此菜单可以让网关服务在sentinel控制台显示不一样的菜单,代码如下:-Dcsp.sentinel.app.type=1

四、特殊菜单中自定义API维度限流

作用:自定义API分组,是一种更细粒度的限流规则定义,它允许我们利用sentinel提供的API,将请求路径进行分组,然后在组上设置限流规则

第一步:新建API分组

第二步:新建分组流控规则

第三步:定制流控网关返回值

@Configuration

public class GatewayConfig {

    public GatewayConfig(){

        GatewayCallbackManager.setBlockHandler( new BlockRequestHandler() {

            @Override

            public Mono<ServerResponse>  handleRequest(
                                                     ServerWebExchangeserverWebExchange,
                                                     Throwable throwable) {

                Map<String,Object> map=new HashMap<>();

                map.put("state",429);

                map.put("message","two many request");

                String jsonStr=JSON.toJSONString(map);

                return ServerResponse.ok().body(Mono.just(jsonStr),String.class);

            }

        });

    }

}

五、定制流控网关返回值

1、设置拦截条件,返回true放行,返回false表示拦截
/*MVC中的拦截器对象*/
@Slf4j
public class TimeAccessInterceptor implements HandlerInterceptor {

    /*此方法在执行目标controller方法之前执行,返回值为true表示放行该请求*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        LocalTime now= LocalTime.now();//JDK8中的时间对象(推荐使用)
        int hour=now.getHour();//获取当前时间对应小时
        //System.out.println("hour="+hour);
        log.info("hour {}",hour);
        /*在规定时间范围内(6点到22点)允许访问,将请求放行*/
        if(hour<=6||hour>=22)
            throw new RuntimeException("请在6~10点进行访问");
        return true;
    }
}
被限流时定制返回错误信息

@Configuration

public class GatewayConfig {

  public GatewayConfig(){

    GatewayCallbackManager.setBlockHandler( new BlockRequestHandler(){

        @Override

       public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {

                Map<String,Object> map=new HashMap<>();

                map.put("state",429);

                map.put("message","two many request");

                String jsonStr=JSON.toJSONString(map);

   return ServerResponse.ok().body(Mono.just(jsonStr),String.class);

            }

        });

    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

S Y H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值