微服務(wù)之--spring-cloud-sleuth

相信在看sleuth的小伙伴們肯定已經(jīng)對(duì)微服務(wù)有一個(gè)大致的了解了迫靖,因此這篇文章會(huì)主要記錄spring-cloud-sleuth矩欠,以及在使用過程當(dāng)中用到的EurekaFeign吮便。

調(diào)用鏈

隨著服務(wù)的拆分邓了,系統(tǒng)的模塊變得越來越多始绍,不同的微服務(wù)可能是不同的人來維護(hù)拔恰,也就造成了當(dāng)我們請(qǐng)求某一個(gè)微服務(wù)的某一個(gè)接口時(shí),可能是調(diào)用了多個(gè)微服務(wù)闹获∑谌基于Google Dapper論文,用戶每次請(qǐng)求都會(huì)生成一個(gè)全局ID(traceId)避诽,通過它將不同系統(tǒng)的“孤立”的日志串在一起龟虎,重組成調(diào)用鏈。
簡(jiǎn)單的說調(diào)用鏈就是當(dāng)我們發(fā)起某個(gè)請(qǐng)求后沙庐,調(diào)用的微服務(wù)的先后順序組成的一個(gè)調(diào)用鏈路鲤妥。

記錄調(diào)用鏈的益處

一個(gè)請(qǐng)求可能會(huì)涉及n多個(gè)微服務(wù)的協(xié)同處理,牽扯到多人甚至多個(gè)團(tuán)隊(duì)的業(yè)務(wù)系統(tǒng)拱雏,一旦中間某個(gè)環(huán)節(jié)出現(xiàn)問題棉安,還得從頭查起。如何可以快速的定位到到底是哪個(gè)微服務(wù)出現(xiàn)的問題铸抑,咱們記錄下來的調(diào)用鏈既可以幫助我們進(jìn)行快速的分析垂券。
除此之外還可以根據(jù)此分析各個(gè)調(diào)用環(huán)節(jié)的性能問題和數(shù)據(jù)分析(調(diào)用鏈?zhǔn)敲看握?qǐng)求的一條完整的業(yè)務(wù)日志,可以得到用戶的行為路徑,匯總分析應(yīng)用的很多業(yè)務(wù)場(chǎng)景)等菇爪。

由于我們今天的主角實(shí)際上就是對(duì)Zipkin的封裝算芯,因此我們先來看下Zipkin的介紹:

Zipkin的設(shè)計(jì)背景

2010年谷歌發(fā)表了其內(nèi)部使用的分布式跟蹤系統(tǒng)Dapper的論文,講述了Dapper在谷歌內(nèi)部?jī)赡甑难葑兒驮O(shè)計(jì)凳宙、運(yùn)維經(jīng)驗(yàn)熙揍,Twitter也根據(jù)該論文開發(fā)了自己的分布式跟蹤系統(tǒng)Zipkin,并將其開源氏涩。

Zipkin的設(shè)計(jì)
圖片.png

上圖為zipkin官網(wǎng)中的結(jié)構(gòu)圖届囚,從上圖我們可以看出數(shù)據(jù)是由各個(gè)應(yīng)用,中間件甚至是數(shù)據(jù)庫(kù)將跟蹤數(shù)據(jù)發(fā)送到Zipkin服務(wù)器是尖,而不是各個(gè)服務(wù)記錄后意系,當(dāng)一條調(diào)用鏈路結(jié)束后統(tǒng)一發(fā)送到Zipkin服務(wù)器的,這樣由Zipkin來分析匯總變成調(diào)用鏈的好處是可以防止某一次請(qǐng)求調(diào)用服務(wù)特別多或者很復(fù)雜的情況下統(tǒng)一發(fā)送造成的性能問題饺汹。

簡(jiǎn)單的服務(wù)調(diào)用實(shí)例
圖片.png

上圖描述的服務(wù)調(diào)用場(chǎng)景應(yīng)該是很常見也很簡(jiǎn)單的調(diào)用場(chǎng)景了蛔添,一個(gè)請(qǐng)求通過Gateway服務(wù)路由到下游的Service1,然后Service1先調(diào)用服務(wù)Service2兜辞,拿到結(jié)果后再調(diào)用服務(wù)Service3迎瞧,最后組合Service2和Service3服務(wù)的結(jié)果,通過Gateway返回給用戶逸吵。我們用①②③④⑤⑥表示了調(diào)用的順序凶硅,什么是span?span直譯過來是"跨度"扫皱,在谷歌的Dapper論文中表示跟蹤樹中樹節(jié)點(diǎn)引用的數(shù)據(jù)結(jié)構(gòu)體足绅,span是跟蹤系統(tǒng)中的基本數(shù)據(jù)單元,Dapper的論文中韩脑,并沒有具體介紹span中的全部細(xì)節(jié)氢妈,但在Zipkin中,每個(gè)span中一般包含如下字段:
traceId:全局跟蹤ID扰才,用它來標(biāo)記一次完整服務(wù)調(diào)用,所以和一次服務(wù)調(diào)用相關(guān)的span中的traceId都是相同的厕怜,Zipkin將具有相同traceId的span組裝成跟蹤樹來直觀的將調(diào)用鏈路圖展現(xiàn)在我們面前衩匣。這里直接給出Zipkin官網(wǎng)中的一張Zipkin界面的圖:
id:span的id,理論上來說粥航,span的id只要做到一個(gè)traceId下唯一就可以琅捏,比如說阿里的鷹眼系統(tǒng)巧妙用span的id來體現(xiàn)調(diào)用層次關(guān)系(例如0,0.1递雀,0.2柄延,0.1.1等),但Zipkin中的span的id則沒有什么實(shí)際含義。
parentId:父span的id搜吧,調(diào)用有層級(jí)關(guān)系市俊,所以span作為調(diào)用節(jié)點(diǎn)的存儲(chǔ)結(jié)構(gòu),也有層級(jí)關(guān)系滤奈,就像上圖所示摆昧,跟蹤鏈?zhǔn)遣捎酶櫂涞男问絹碚宫F(xiàn)的,樹的根節(jié)點(diǎn)就是調(diào)用的頂點(diǎn)蜒程,從開發(fā)者的角度來說绅你,頂級(jí)span是從接入了Zipkin的應(yīng)用中最先接觸到服務(wù)調(diào)用的應(yīng)用中采集的。所以昭躺,頂級(jí)span是沒有parentId字段的忌锯,拿上圖所展現(xiàn)的例子來說,頂級(jí)span由Gateway來采集领炫,Service1的span是它的子span偶垮,而Service2和Service3的span是Service1的span的子span,很顯然Service2和Service3的span是平級(jí)關(guān)系驹吮。
name:span的名稱针史,主要用于在界面上展示,一般是接口方法名碟狞,name的作用是讓人知道它是哪里采集的span啄枕,不然某個(gè)span耗時(shí)高我都不知道是哪個(gè)服務(wù)節(jié)點(diǎn)耗時(shí)高。
timestamp:span創(chuàng)建時(shí)的時(shí)間戳族沃,用來記錄采集的時(shí)刻频祝。
duration:持續(xù)時(shí)間,即span的創(chuàng)建到span完成最終的采集所經(jīng)歷的時(shí)間脆淹,除去span自己邏輯處理的時(shí)間常空,該時(shí)間段可以理解成對(duì)于該跟蹤埋點(diǎn)來說服務(wù)調(diào)用的總耗時(shí)。
annotations:基本標(biāo)注列表盖溺,一個(gè)標(biāo)注可以理解成span生命周期中重要時(shí)刻的數(shù)據(jù)快照漓糙,比如一個(gè)標(biāo)注中一般包含發(fā)生時(shí)刻(timestamp)员舵、事件類型(value)对蒲、端點(diǎn)(endpoint)等信息,這里給出一個(gè)標(biāo)注的json結(jié)構(gòu):
{
"timestamp": 1476197069680000,
"value": "cs",
"endpoint": {
"serviceName": "service1",
"ipv4": "xxx.xxx.xxx.111"
}
}
四種事件類型:cs(客戶端/消費(fèi)者發(fā)起請(qǐng)求)择卦、cr(客戶端/消費(fèi)者接收到應(yīng)答)蝇庭、sr(服務(wù)端/生產(chǎn)者接收到請(qǐng)求)和ss(服務(wù)端/生產(chǎn)者發(fā)送應(yīng)答)醉鳖。可以看出哮内,這四種事件類型的統(tǒng)計(jì)都應(yīng)該是Zipkin提供客戶端來做的盗棵,因?yàn)檫@些事件和業(yè)務(wù)無(wú)關(guān),這也是為什么跟蹤數(shù)據(jù)的采集適合放到中間件或者公共庫(kù)來做的原因。
binaryAnnotations:業(yè)務(wù)標(biāo)注列表纹因,如果某些跟蹤埋點(diǎn)需要帶上部分業(yè)務(wù)數(shù)據(jù)(比如url地址喷屋、返回碼和異常信息等),可以將需要的數(shù)據(jù)以鍵值對(duì)的形式放入到這個(gè)字段中辐怕。

接下來進(jìn)入正題,記錄一下spring-cloud-sleuth在工程中的使用:
1.首先創(chuàng)建一個(gè)zipkinserver工程逼蒙,在pom文件中添加如下依賴:

        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
        </dependency>

        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
        </dependency>
//這個(gè)是用來自動(dòng)適配版本的
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

在配置文件中添加如下配置:

server.port=32071
spring.application.name=zipkinService 
#設(shè)置采樣率,測(cè)試時(shí)可將此設(shè)置為1寄疏,表示每條請(qǐng)求都記錄下來
spring.sleuth.sampler.percentage=0.2

在主程序入口處添加注解@EnableZipkinServer
2.創(chuàng)建一個(gè)helloserver工程是牢,在pom文件中添加如下依賴:

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
        </dependency>
    

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

在配置文件中添加如下配置:

server.port=8988
spring.zipkin.base-url=http://localhost:32071
spring.application.name=service-hello

新建一個(gè)接口類,并實(shí)現(xiàn)如下方法:

@RestController
@RequestMapping("/servicehello")
public class controller
{
    private static final Logger LOG = Logger.getLogger(controller.class.getName());


    @Autowired
    private RestTemplate restTemplate;

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

    @RequestMapping("/hello")
    public String callHome(){
        LOG.log(Level.INFO, "calling trace service-hi  ");
        return restTemplate.getForObject("http://localhost:8989/servicehi/hi", String.class);
    }
    @RequestMapping("/test")
    public String info(){
        LOG.log(Level.INFO, "calling trace service-hello ");

        return "i'm service-hello";
    }
    @Bean
    public AlwaysSampler defaultSampler(){
        return new AlwaysSampler();
    }
}

3.創(chuàng)建hiserver工程陕截,在pom文件中添加和2中相同
在配置文件中設(shè)置如下:

server.port=8989
spring.zipkin.base-url=http://localhost:32071
spring.application.name=service-hi

添加請(qǐng)求類并實(shí)現(xiàn)如下方法:

@RestController
@RequestMapping("/servicehi")
public class controller {
    private static final Logger LOG = Logger.getLogger(ServiceHiApplication.class.getName());


    @Autowired
    private RestTemplate restTemplate;

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

    @RequestMapping("/hi")
    public String callHome(){
        LOG.log(Level.INFO, "calling trace service-hello  ");
        return restTemplate.getForObject("http://localhost:8988/servicehello/test", String.class);
//        LOG.log(Level.INFO, "calling trace service-new  ");
//        return restTemplate.getForObject("http://localhost:32061/Designer/getPromotionlist/?orgid=283", String.class);
    }
    @RequestMapping("/info")
    public String info(){
        LOG.log(Level.INFO, "calling trace service-hi ");

        return "i'm service-hi";
    }

    @Bean
    public AlwaysSampler defaultSampler(){
        return new AlwaysSampler();
    }

}

依次運(yùn)行這三個(gè)項(xiàng)目驳棱,然后訪問接口如下結(jié)果:

CUF891OOFH@3VO8%D7EQ$KH.png

訪問依次這個(gè)接口后我們可以看到localhost:32071的頁(yè)面變成如下樣子:

K}SO)@O%CR)R)700V6K_KEJ.png

點(diǎn)擊進(jìn)入詳情頁(yè):

{5({JH0KDLI)EW_DOYWQHLT.png

如上圖可以清晰的看到到底是哪個(gè)服務(wù)的哪個(gè)方法調(diào)用的哪個(gè)服務(wù)的哪個(gè)方法。接下來咱們看一下依賴關(guān)系(直接點(diǎn)擊上面圖中最上面一行的Dependentices):

依賴關(guān)系.png

上面的例子主要是通過RestTemplate來調(diào)用其他服務(wù)的农曲,接下來我們看一下如果使用Feign來調(diào)用其他服務(wù)怎么使用spring-cloud-sleuth來監(jiān)控器調(diào)用過程社搅。

接下來我們使用feign來調(diào)用其他服務(wù)

修改原來的hiserver,zipkinserver,工程,并新建spring-cloud-eureka,spring-cloud-feign工程乳规。
1.新建spring-cloud-eureka工程
在pom文件中添加依賴如下:

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

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

在配置文件中添加如下配置(application.properties):

server.port=11111
eureka.client.service-url.defaultZone:http://localhost:11111/eureka/
spring.application.name=eureka-server

在程序入口文件中添加注解@EnableEurekaServer后運(yùn)行該項(xiàng)目后可看到界面如下:

eureka.png

2.新建spring-cloud-feign工程形葬,并在pom文件中添加如下依賴:

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

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
        </dependency>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

然后在配置文件中增加如下配置:

server.port=11112
#配置eureka地址
eureka.client.service-url.defaultZone:http://localhost:11111/eureka/
spring.application.name=feign-server
#配置zipkin地址
spring.zipkin.base-url=http://localhost:32071
#配置采樣率
spring.sleuth.sampler.percentage=1.0

創(chuàng)建一個(gè)接口類如下:

//此注解后面的value值是想要調(diào)用的服務(wù)的名稱,也就是在配置文件中的spring.application.name
@FeignClient(value = "service-hi")
public interface schedualservicehi {
//此value后面是你想調(diào)用微服務(wù)的接口地址
    @RequestMapping(value = "/servicehi/info",method = RequestMethod.GET)
//此接口相當(dāng)于中間層暮的,通過訪問此接口便可以訪問到上面配置的服務(wù)路徑
    String sayHiFromClientOne();
}

接下來創(chuàng)建一個(gè)類笙以,在此類中測(cè)試方法調(diào)用

@RestController
public class controller {
    @Autowired
    schedualservicehi schedualservicehi;
    @RequestMapping(value = "/feign",method = RequestMethod.GET)
    public String sayInfo(){
        return schedualservicehi.sayHiFromClientOne();
    }

最后在工程入口文件中添加注解如下:

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication

public class SpringcloudfeignApplication {

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

3.在hiserver工程中做如下修改:
pom文件中除了之前添加的有關(guān)zipkin的依賴外再添加如下:

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

配置文件中再增加如下:

server.port=8989
spring.zipkin.base-url=http://localhost:32071
spring.application.name=service-hi
eureka.client.service-url.defaultZone:http://localhost:11111/eureka/
spring.sleuth.sampler.percentage=1.0

工程入口文件中添加注解

@SpringBootApplication
@EnableEurekaClient
public class ServiceHiApplication {

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

其他的不用剛修改,再次運(yùn)行這幾個(gè)工程:
訪問feign的接口:

feign.png

然后再看ereuka的界面冻辩,發(fā)現(xiàn)其他項(xiàng)目也已經(jīng)注冊(cè)上

eureka.png

再來看一下sleuth的界面出現(xiàn)了剛才咱們?cè)L問feign的那個(gè)接口的記錄:

調(diào)用鏈.png

點(diǎn)擊一條記錄看一下依賴關(guān)系:

依賴關(guān)系 (2).png

以上結(jié)果均正確猖腕,說明sleuth可以監(jiān)控到使用feign來調(diào)用服務(wù)的調(diào)用鏈路

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市恨闪,隨后出現(xiàn)的幾起案子倘感,更是在濱河造成了極大的恐慌,老刑警劉巖咙咽,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件老玛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钧敞,警方通過查閱死者的電腦和手機(jī)蜡豹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犁享,“玉大人余素,你說我怎么就攤上這事豹休〈独ィ” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)凤巨。 經(jīng)常有香客問我视乐,道長(zhǎng),這世上最難降的妖魔是什么敢茁? 我笑而不...
    開封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任佑淀,我火速辦了婚禮,結(jié)果婚禮上彰檬,老公的妹妹穿的比我還像新娘伸刃。我一直安慰自己,他們只是感情好逢倍,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開白布捧颅。 她就那樣靜靜地躺著,像睡著了一般较雕。 火紅的嫁衣襯著肌膚如雪碉哑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天亮蒋,我揣著相機(jī)與錄音扣典,去河邊找鬼。 笑死慎玖,一個(gè)胖子當(dāng)著我的面吹牛贮尖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凄吏,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼远舅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了痕钢?” 一聲冷哼從身側(cè)響起图柏,我...
    開封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎任连,沒想到半個(gè)月后蚤吹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡随抠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年裁着,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拱她。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡二驰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秉沼,到底是詐尸還是另有隱情桶雀,我是刑警寧澤矿酵,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站矗积,受9級(jí)特大地震影響全肮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棘捣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一辜腺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乍恐,春花似錦评疗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瞧毙,卻和暖如春胧华,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宙彪。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工矩动, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人释漆。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓悲没,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親男图。 傳聞我的和親對(duì)象是個(gè)殘疾皇子示姿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容