欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

程序员文章站 2022-07-05 14:16:57
在上一篇文章中,我们搭建了Hystrix Dashoard,对指定接口进行监控。但是只能对一个接口进行监听,功能比较局限; Turbine:汇总系统内多个服务的数据并显示到 Hystrix Dashboard 上。虽然可以实现对消费者的聚合监控,但是如果新增了消费者,也需要对其进行监控,就需要重新启 ......

在上一篇文章中,我们搭建了hystrix dashoard,对指定接口进行监控。但是只能对一个接口进行监听,功能比较局限;

turbine:汇总系统内多个服务的数据并显示到 hystrix dashboard 上。虽然可以实现对消费者的聚合监控,但是如果新增了消费者,也需要对其进行监控,就需要重新启动项目,这是非常不合理的。

改造后的turbine项目:本文将进行对turbine的改造,在原有的功能上实现登录认证、实时监控的功能,使turbine项目在不用重启的情况下都可以获取最新的、完整的服务消费情况。

准备项目:

 1. eureka-service:eureka注册中心,端口:8761,用于服务注册与发现;

         2. eureka-provider_1:服务提供者1,端口:8071,用于提供服务;

         3. eureka-provider_2:服务提供者2,端口:8072,用于提供服务;

         4. ribbon-consumer-hystrix-1:服务消费者1,端口:9001,用于消费服务;

    5. ribbon-consumer-hystrix-2:服务消费者2,店口:9002,用于消费服务;

         6. readlocalproperties:用于读取本地文件,端口:9999;

    7. turbine-dashboard:断后改造后的hystrix dashboard客户端项目,端口:7979。

         1-3个项目可参考自行创建,或者从下文附件中下载。我们详细讲下ribbon-consumer-hystrix-1、ribbon-consumer-hystrix-2、readlocalproperties项目、turbine-dashboard项目的构建;

         重要注释在代码中,就不另外叙述了。

 一、搭建ribbon-consumer-hystrix-1项目:

        1. 在pom.xml中添加如下依赖:   

<!-- 客户端负载均衡 -->
        <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-starter-ribbon</artifactid>
        </dependency>
        <!-- eureka客户端 -->
        <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-starter-eureka</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-starter-hystrix</artifactid>
        </dependency>
         <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-test</artifactid>
            <scope>test</scope>
        </dependency> 
        <dependency>
            <groupid>com.google.code.gson</groupid>
            <artifactid>gson</artifactid>
            <version>2.5</version>
        </dependency>

        <dependency>
            <groupid>org.slf4j</groupid>
            <artifactid>slf4j-api</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-actuator</artifactid>
        </dependency>

2.配置文件:

eureka:
  client:
    serviceurl:
      defaultzone: http://localhost:8761/eureka/
  instance:
    leaseexpirationdurationinseconds: 4  
    leaserenewalintervalinseconds: 1  
spring:
  application:
    name: ribbon-consumer-hystrix

server:
  port: 9001
#用于存入本地文件,供readlocalproperties项目读取并调用
url: http://localhost:9001/sendmsg

3.启动类: 

 1 @enablehystrix
 2 @enablediscoveryclient
 3 @springbootapplication
 4 public class ribbonconsumerapplication_1 {
 5     
 6     @loadbalanced
 7     @bean
 8     resttemplate resttemplate() {
 9         return new resttemplate();
10     }
11 
12     public static void main(string[] args) {
13         springapplication.run(ribbonconsumerapplication_1.class, args);
14         writeconfig();
15     }
16     //读取调用该jar包的项目中配置文件的url,存入指定文件,供readlocalproperties项目读取
17     public static void writeconfig (){
18         properties prop=new properties();
19         try {
20             prop.load(config.class.getresourceasstream("/application.yml"));
21         } catch (ioexception e2) {
22             // todo auto-generated catch block
23             e2.printstacktrace();
24         }
25         string url="";
26       
27          url=prop.getproperty("url");
28         
29          system.out.println("url---"+url);
30         //读取文件中已有的url
31         properties propp=new properties();
32         string oldurl="";
33         try {
34         inputstream ins = new fileinputstream(new file("f:\\config.properties"));
35         propp.load(ins);
36       
37          oldurl=propp.getproperty("url");
38           system.out.println("oldurl---"+oldurl);
39             ins.close();
40         } catch (filenotfoundexception e1) {
41             // todo auto-generated catch block
42             e1.printstacktrace();
43         
44         } catch (ioexception e1) {
45             // todo auto-generated catch block
46             e1.printstacktrace();        
47         }
48         
49         //拼接原来的url和新的url
50           try {   
51              // 调用 hashtable 的方法 put,使用 getproperty 方法提供并行性。   
52              // 强制要求为属性的键和值使用字符串。返回值是 hashtable 调用 put 的结果。   
53             fileoutputstream fos = new fileoutputstream("f:\\config.properties",false);  
54             system.out.println("fos---"+fos);
55             properties pro = new properties();
56          
57             int ifhas=0;
58             if(com.google.common.base.strings.isnullorempty(oldurl)) {
59                 oldurl= ",";
60             }
61             string[] strs=oldurl.split(",");
62             for(int i=0;i<strs.length;i++) {
63                 if(url.equals(strs[i])) {
64                     ifhas=1;
65                 }
66             }
67             //如果配置文件中未存在该接口
68             string newurl="";
69             if(ifhas==0) {
70                 // 存储
71                 newurl=oldurl+","+url;//拼接已存在的urls和新的url
72             }else {
73                 newurl=oldurl;
74             }
75             pro.setproperty("url", newurl);
76             // 以适合使用 load 方法加载到 properties 表中的格式,   
77             // 将此 properties 表中的属性列表(键和元素对)写入输出流   
78                pro.store(fos, newurl);  
79                fos.close();
80          } catch (ioexception e) {   
81              system.err.println("属性文件更新错误");   
82          }   
83          
84     }
85 }

4. 控制层:编写接口(此处以/hello为例)消费服务,编写接口用于组装监控面板监控对象,实现自动注册到turbine聚合监控面板上的功能。

监控面板监控对象,包括以下信息:

name:监控详情页显示的hystrix stream名称

stream:需要监控的服务接口

auth:作者

delay:获取监控数据间隔时间

@restcontroller
public class consumercontroller {

    @autowired
    private resttemplate resttemplate;

    //创建了熔断器的功能 ,并指定了defaultstores熔断方法
    //@hystrixcommand 表明该方法为hystrix包裹,
    //可以对依赖服务进行隔离、降级、快速失败、快速重试等等hystrix相关功能 
    //fallbackmethod 降级方法
    //commandproperties 普通配置属性,可以配置hystrixcommand对应属性,例如采用线程池还是信号量隔离、熔断器熔断规则等等
    //ignoreexceptions 忽略的异常,默认hystrixbadrequestexception不计入失败
    //groupkey() 组名称,默认使用类名称
    //commandkey 命令名称,默认使用方法名    
    @hystrixcommand(fallbackmethod = "defaultstores")
    @getmapping(value = "/hello")
    public string hello(throwable throwable) {
        return resttemplate.getforentity("http://eureka-provider/", string.class).getbody();
    }

    //熔断方法直接返回了一个字符串, "feign + hystrix ,提供者服务挂了"
    public string defaultstores(throwable throwable) {
        return "ribbon + hystrix ,提供者服务挂了";
    }
    //用于组装监控面板监控对象,实现自动注册到turbine聚合监控面板上的功能。
    @requestmapping(value = "/sendmsg")
    public string sendmessage(httpservletrequest request) {
        jsonobject lan=new jsonobject();
        lan.addproperty("name", "9001");
        lan.addproperty("stream", "http://127.0.0.1:9001/hystrix.stream");
        lan.addproperty("auth", "test");
        lan.addproperty("delay", "2000");
        system.out.println("jaon-lan------"+lan);
        return "callback("+lan+")";
    }
}

二、搭建ribbon-consumer-hystrix-2项目:

       做法同一,配置文件端口和sendmessage方法中端口改成9002。

三、搭建readlocalproperties项目:

        1. 在pom.xml中添加如下依赖: 

<dependency>
    <groupid>org.springframework.cloud</groupid>
     <artifactid>spring-cloud-starter-eureka</artifactid>
</dependency> 

         2.配置文件:

eureka:
  client:
    serviceurl:
      defaultzone: http://localhost:8761/eureka/
  instance:
    leaseexpirationdurationinseconds: 4  
    leaserenewalintervalinseconds: 1  
spring:
  application:
    name: ribbon-consumer-hystrix-dashbord

server:
  port: 9999

        3.启动类: 

@enablediscoveryclient
@springbootapplication
public class readapplication {
    public static void main(string[] args) {
        springapplication.run(readapplication.class, args);
    }
}

4.控制层:编写接口实现从本地文件中读取接口列表。用于获取消费者注册信息,供turbine项目调用。

@restcontroller
public class consumercontroller {
    @requestmapping(value = "/read")
    public string read(httpservletrequest request) {
        // 读取文件中已有的url
        properties propp = new properties();
        string oldurl = "";
        try {
            inputstream ins = new fileinputstream(new file("f:\\config.properties"));
            propp.load(ins);
            oldurl = propp.getproperty("url");
            system.out.println("oldurl---" + oldurl);
            ins.close();
        } catch (filenotfoundexception e1) {
            // todo auto-generated catch block
            e1.printstacktrace();
        } catch (ioexception e1) {
            // todo auto-generated catch block
            e1.printstacktrace();
        }
        return "readcallback(\"" + oldurl + "\")";
    }
}

 四、重点改造搭建turbine-dashboard项目:

        项目首先导入turbine项目,然后我们对其前端进行改造,通过ajax跨域请求readlocalproperties项目,读取本地文件f:\\config.properties中的urls,然后在监控面板中显示。

         还记得读取本地文件f:\\config.properties中的urls是什么时候添加的吗?忘记的同学可以往上翻,懒得翻的同学我告诉你,就是在消费者项目启动时,通过writeconfig()方法将配置文件中的url添加到本地文件。

         那配置文件中url的是什么呢?忘记的同学可以往上翻,懒得翻的同学我告诉你,配置文件中url是该项目封装的监控对象信息。当turbine-dashboard项目启动后,会从本地文件中读取这些url,然后获取一个个需要监控的对象,从而显示在监控面板上。

       1.项目结构:这里的项目结构是我改造后的)

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

      2.登录页面:

      后端:修改/hystrix_dashboard路径的路由,使之路由到login.html,进行登录认证。

    改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

      前端:新建login.html页面,进行登录认证,并将登录信息存入cookie。

 1 <html>
 2 <head>
 3 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 4 <title>登录</title>
 5 </head>
 6 <script type="text/javascript">
 7     function validatelogin() {
 8         var username = document.getelementbyid('username').value;
 9         var password = document.getelementbyid('password').value;
10         if (username == "" || password == "") {
11             alert("请输入用户名密码!");
12             return false;
13         } else if (username != 'admin' || password != "admin") {
14             alert("用户名密码不正确!");
15             return false;
16         } else {
17             setcookie('username',username,10);//cookie保存10分钟
18             setcookie('password',password,10);//cookie保存10分钟
19             //校验成功进入监控面板主页
20             location.href = "/hystrix-dashboard/main";
21         /*     location.href = "/hystrix-dashboard/main?username=" + username
22                     + "&&password=" + password; */
23         }
24     }
25     /* 创建和存储 cookie */
26     function setcookie(c_name, value, expire) {
27         var exdate = new date()
28         exdate.settime(exdate.gettime()+expire*60*1000); //设置date为当前时间分钟
29     //    exdate.setdate(exdate.gethour() + expiredays)
30         document.cookie = c_name
31                 + "="
32                 + escape(value)
33                 + ((expire == null) ? "" : ";expires="
34                         + exdate.togmtstring())
35     }
36     /* 检查是否已设置 cookie */
37     function getcookie(c_name)
38     {
39     if (document.cookie.length>0)
40       {
41       c_start=document.cookie.indexof(c_name + "=")
42       if (c_start!=-1)
43         { 
44         c_start=c_start + c_name.length+1 
45         c_end=document.cookie.indexof(";",c_start)
46         if (c_end==-1) c_end=document.cookie.length
47         return unescape(document.cookie.substring(c_start,c_end))
48         } 
49       }
50     return ""
51     }
52     
53 </script>
54 <body>
55     <div style="width: 800px; margin: 0 auto;">
56         <center>
57             <img width="264" height="233" src="images/hystrix-logo.png">
58             <br> <br>
59             <br> <br>
60             <h2>hystrix dashboard</h2>
61         </center>
62     </div>
63     <center>
64         <form id="form" action="/hystrix-dashboard/test" method="post"></form>
65         <table>
66             <tr>
67                 <td>username:</td>
68                 <td><input type="text" name="username" id="username" size="20"
69                     maxlength="20" /></td>
70             </tr>
71             <tr>
72                 <td>password:</td>
73                 <td><input type="password" name="password" id="password"
74                     size="20" maxlength="20" /></td>
75             </tr>
76 
77             <tr>
78                 <td><input type="submit" name="login" value="login"
79                     style="margin-top: 50%; margin-left: 150%"
80                     onclick="return validatelogin()" /></td><!-- 进行登录校验 -->
81             </tr>
82 
83         </table>
84         </form>
85     </center>
86 
87 </body>
88 </html>

       3.改造项目中的监控面板主页、监控详情页

     后端:对/main(监控面板主页)、/monitor(监控详情页)路径进行cookie认证

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

     前端:获取需要监控的对象

 1     $(function(){
 2         $('#streams').html('<table id="hystrix_list"></table>');
 3     })
 4     //跨域请求read接口,获取本地文件中存储的urls
 5     $.getjson("http://127.0.0.1:9999/read?jsoncallback=?");
 6     function readcallback(url){
 7         alert("read.url--"+url);
 8         var strs= new array();
 9         strs=url.split(",");
10         for (i=0;i<strs.length ;i++ ) 
11         { 
12              if(strs[i]!="null"){
13                $.getjson(strs[i]+"?jsoncallback=?");   //$.getjson("http://localhost:9000/sendmessage?jsoncallback=?");
14              }else{
15                  continue;
16              }
17         }
18     }
19     //跨域请求本地文件中存储的urls,获取需要进行监控的对象
20     function callback(data){
21         c={
22                 name:data.name,
23                 stream: data.stream,
24                 auth: data.auth,
25                 delay: data.delay
26         }; 
27         streams.push(c);
28         /*  $('#streams').html('<table>' + _.reduce(streams, function(html, c) {
29             return html + '<tr><td>' + c.name + '</td><td>' + c.stream + '</td> <td><a href="#" onclick="removestream(this);">remove</a></td> </tr>';
30 }, '') + '</table>');  */
31 
32         $("#hystrix_list").append('<tr><td>' + c.name + '</td><td>' + c.stream + '</td> <td><a href="#" onclick="removestream(this);">remove</a></td> </tr>'); 
33     }
34         //添加需要监控的stream
35         function addstream () {
36             if ($('#stream').val().length > 0) {
37                 var s = {
38                     name: $('#title').val(),
39                     stream: $('#stream').val(),
40                     auth: $('#authorization').val(),
41                     delay: $('#delay').val()
42                 }; 
43                 streams.push(s);
44                 /* $('#streams').html('<table>' + _.reduce(streams, function(html, s) {
45                             return html + '<tr><td>' + s.name + '</td><td>' + s.stream + '</td> <td><a href="#" onclick="removestream(this);">remove</a></td> </tr>';
46                 }, '') + '</table>'); */
47                 $("#hystrix_list").append('<tr><td>' + s.name + '</td><td>' + s.stream + '</td> <td><a href="#" onclick="removestream(this);">remove</a></td> </tr>');
48                 $('#title').val("");
49                 $('#stream').val("");
50                 $('#authorization').val("");
51                 $('#delay').val("");
52                 $('#message').html("");
53             } else {
54                 $('#message').html("the 'stream' value is required.");
55             }
56         }

 五、启动步骤:

       1. 依次启动eureka-service、eureka-provider_1、eureka-provider_2、ribbon-consumer-hystrix-1、ribbon-consumer-hystrix-2、readlocalproperties项目 :

        可以看见eureka监控面板都注册上了这五个服务:

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

           打开本地配置文件f:\\config.properties,可以看见两个消费者项目的获取监控对象的url已经保存在本地文件了:

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

2.启动turbine-dashboard项目:

由于我们在浏览器输入的地址是http://localhost:7979/hystrix-dashboard/,经上文我们改造过后,路由到了登录页面。

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

              接下来我们输入代码中设置好的用户名密码,admin/admin,再点击login,结果进入到了监控主页:啊!又是这只恶狠狠的刺猬熊呢! 

              并且,我们可以看到在主页下方已经自动添加了两个监控对象,这就是我们之前在启动消费者对象的时候,保存的对象,当我们打开监控面板时获取到页面上了。

              当然你也可以在此页面上手动添加和删除,然后直接点击“monitor stream”就可以进入监控详情页。

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

               下图为未改造前的监控面板主页,需要手动添加监控对象。

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

        点击“monitor stream”就可以进入监控详情页:

        可以发现turbine dashboard项目实现了集群监控。

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

               还没结束,为了测试是否实现消费者自动注册到turbine,我们在turbine项目启动的情况下,直接启动端口为9005的消费者项目,随后返回turbine监控主页面进行刷新,刷新后页面如下:

               监控主页添加了一个新的消费者对象。

改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

               进入监控详情页,开始监控所有消费者对象。

 改造断路器集群监控Hystrix Turbine实现自动注册消费者、实时监控多个服务

虽然是在原来项目上已经做了改造,但是实际用的话还需要优化,比如登录用户密码、本地文件存储地址等可以写在配置文件中,从而可以根据不同环境进行打包等。

总之。。。有待改进

 

 最后,附上本文用到的所有项目:newturbine.zip

链接:https://pan.baidu.com/s/1mamx5d77towvphzbcbeqsg
提取码:xxdz