首頁常見問題正文

還在用Zipkin分布式服務鏈路追蹤?來試試這個吧!

更新時間:2023-10-23 來源:黑馬程序員 瀏覽量:

  自SpringCloud問世以來,微服務以席卷之勢風靡全球,企業(yè)架構都在從傳統(tǒng)SOA向微服務轉型。然而微服務這把雙刃劍在帶來各種優(yōu)勢的同時,也給運維、性能監(jiān)控、錯誤的排查帶來的極大的困難。

  在大型項目中,服務架構會包含數(shù)十乃至上百個服務節(jié)點。往往一次請求會設計到多個微服務,想要排查一次請求鏈路中經(jīng)過了哪些節(jié)點,每個節(jié)點的執(zhí)行情況如何,就稱為了亟待解決的問題。于是分布式系統(tǒng)的APM管理系統(tǒng)應運而生。

  什么是APM系統(tǒng)?

  APM系統(tǒng)可以幫助理解系統(tǒng)行為、用于分析性能問題的工具,以便發(fā)生故障的時候,能夠快速定位和解決問題,這就是APM系統(tǒng),全稱是(Application Performance Monitor)。

  谷歌公開的論文提到的 [Google Dapper](http://bigbully.github.io/Dapper-translation)可以說是最早的APM系統(tǒng)了,給google的開發(fā)者和運維團隊幫了大忙,所以谷歌公開論文分享了Dapper。

  而后,很多的技術公司基于這篇論文的原理,設計開發(fā)了很多出色的APM框架,例如`Pinpoint`、`SkyWalking`等。

  而SpringCloud官網(wǎng)也集成了一套這樣的系統(tǒng):`Spring Cloud Sleuth`,結合`Zipkin`。

  APM的基本原理

  目前大部分的APM系統(tǒng)都是基于Google的Dapper原理實現(xiàn),我們簡單來看看Dapper中的概念和實現(xiàn)原理。

  先來看一次請求調用示例:

  1. 服務集群中包括:前端(A),兩個中間層(B和C),以及兩個后端(D和E)

  2. 當用戶發(fā)起一個請求時,首先到達前端A服務,然后A分別對B服務和C服務進行RPC調用;

  3. B服務處理完給A做出響應,但是C服務還需要和后端的D服務和E服務交互之后再返還給A服務,最后由A服務來響應用戶的請求;

1698027580789_圖1.jpg

  如何才能實現(xiàn)跟蹤呢?

  Google的Dapper設計了下面的幾個概念用來記錄請求鏈路:

  - Span:請求中的基本工作單元,每一次鏈路調用(RPC、Rest、數(shù)據(jù)庫調用)都會創(chuàng)建一個Span。大概結構如下:

  type Span struct {
      TraceID    int64 // 用于標示一次完整的請求id
      Name       string // 單元名稱
      ID         int64 // 當前這次調用span_id
      ParentID   int64 // 上層服務的span_id,最上層服務parent_id為null,代表根服務
      Annotation []Annotation // 注釋,用于記錄調用中的詳細信息,例如時間
  }

  - Trace:一次完整的調用鏈路,包含多個Span的樹狀結構,具有唯一的TraceID

  一次請求的每個鏈路,通過spanId、parentId就能串聯(lián)起來:

1698027602609_圖2.jpg

  當然,從請求到服務器開始,服務器返回response結束,每個span存在相同的唯一標識trace_id。

  APM的篩選標準

  目前主流的APM框架都會包含下列幾個組件來完成鏈路信息的收集和展示:

  - 探針(Agent):負責在客戶端程序運行時搜索服務調用鏈路信息,發(fā)送給收集器

  - 收集器(Collector):負責將數(shù)據(jù)格式化,保存到存儲器

  - 存儲器(Storage):保存數(shù)據(jù)

  - UI界面(WebUI):統(tǒng)計并展示收集到的信息

  因此,要篩選一款合格的APM框架,就是對比各個組件的使用差異,主要對比項:

  - 探針的性能

  主要是agent對服務的吞吐量、CPU和內存的影響。如果探針在收集微服務運行數(shù)據(jù)時,對微服務的運行產(chǎn)生了比較大的性能影響,相信沒什么人愿意使用。

  - collector的可擴展性

  能夠水平擴展以便支持大規(guī)模服務器集群,保證收集器的高可用特性。

  - 全面的調用鏈路數(shù)據(jù)分析

  數(shù)據(jù)的分析要快,分析的維度盡可能多。跟蹤系統(tǒng)能提供足夠快的信息反饋,就可以對生產(chǎn)環(huán)境下的異常狀況做出快速反應,最好提供代碼級別的可見性以便輕松定位失敗點和瓶頸。

  - 對于開發(fā)透明,容易開關

  即也作為業(yè)務組件,應當盡可能少入侵或者無入侵其他業(yè)務系統(tǒng),對于使用方透明,減少開發(fā)人員的負擔。

  - 完整的調用鏈應用拓撲

  自動檢測應用拓撲,幫助你搞清楚應用的架構

  接下來,我們就對比下目前比較常見的三種APM框架的各項指標,分別是:

  - [Zipkin](https://link.juejin.im/?target=http%3A%2F%2Fzipkin.io%2F):由Twitter公司開源,開放源代碼分布式的跟蹤系統(tǒng),用于收集服務的定時數(shù)據(jù),以解決微服務架構中的延遲問題,包括:數(shù)據(jù)的收集、存儲、查找和展現(xiàn)。

  - [Pinpoint](https://pinpoint.com/):一款對Java編寫的大規(guī)模分布式系統(tǒng)的APM工具,由韓國人開源的分布式跟蹤組件。

  - [Skywalking](https://skywalking.apache.org/zh/):國產(chǎn)的優(yōu)秀APM組件,是一個對JAVA分布式應用程序集群的業(yè)務運行情況進行追蹤、告警和分析的系統(tǒng)?,F(xiàn)在是Apache的頂級項目之一。

  三者對比如下:

  | 對比項 | zipkin | pinpoint | skywalking |

  | ---------------- | ------ | -------- | ---------- |

  | 探針性能 | 中 | 低 | 高 |

  | collector擴展性 | 高 | 中 | 高 |

  | 調用鏈路數(shù)據(jù)分析 | 低 | 高 | 中 |

  | 對開發(fā)透明性 | 中 | 高 | 高 |

  | 調用鏈應用拓撲 | 中 | 高 | 中 |

  | 社區(qū)支持 | 高 | 中 | 高 |

  可見,zipkin的探針性能、開發(fā)透明性、數(shù)據(jù)分析能力都不占優(yōu),實在是下下之選。

  而pinpoint在數(shù)據(jù)分析能力、開發(fā)透明性上有較大的優(yōu)勢,不過Pinpoint的部署相對比較復雜,需要的硬件資源較高。

  Skywalking的探針性能和開發(fā)透明性上具有較大優(yōu)勢,數(shù)據(jù)分析能力上也還不錯,重要的是其部署比較方便靈活,比起Pinpoint更適合中小型企業(yè)使用。

  Skywalking介紹

  SkyWalking 創(chuàng)建與2015年,提供分布式追蹤功能。從5.x開始,項目進化為一個完成功能的Application Performance Management系統(tǒng)。

  他被用于追蹤、監(jiān)控和診斷分布式系統(tǒng),特別是使用微服務架構,云原生或容積技術。提供以下主要功能:

  - 分布式追蹤和上下文傳輸

  - 應用、實例、服務性能指標分析

  - 根源分析

  - 應用拓撲分析

  - 應用和服務依賴分析

  - 慢服務檢測

  - 性能優(yōu)化

  官網(wǎng)地址:http://skywalking.apache.org/

1698027643122_圖3.jpg

  主要的特征:

  - 多語言探針或類庫

  - Java自動探針,追蹤和監(jiān)控程序時,不需要修改源碼。

  - 社區(qū)提供的其他多語言探針

  - [.NET Core](https://github.com/OpenSkywalking/skywalking-netcore)

  - [Node.js](https://github.com/OpenSkywalking/skywalking-nodejs)

  - 多種后端存儲: ElasticSearch, H2

  - 支持

  OpenTracing

  - Java自動探針支持和OpenTracing API協(xié)同工作

  - 輕量級、完善功能的后端聚合和分析

  - 現(xiàn)代化Web UI

  - 日志集成

  - 應用、實例和服務的告警

  Skywalking的安裝

  先來看下Skywalking的官方給出的結構圖:

1698027668367_圖4.jpg

  大致分四個部分:

  - skywalking-oap-server:就是Observability Analysis Platformd的服務,用來收集和處理探針發(fā)來的數(shù)據(jù)

  - skywalking-UI:就是skywalking提供的Web UI 服務,圖形化方式展示服務鏈路、拓撲圖、trace、性能監(jiān)控等

  - agent:探針,獲取服務調用的鏈路信息、性能信息,發(fā)送到skywalking的OAP服務

  - Storage:存儲,一般選擇elasticsearch

  Skywalking支持windows或者Linux環(huán)境部署。這里我們選擇在Linux下安裝Skywalking,大家要先確保自己的Linux環(huán)境中有elasticsearch在啟動中。

  接下來的安裝分為三步:

  - 下載安裝包

  - 安裝Skywalking的OAP服務和WebUI

  - 在服務中部署探針

  下載安裝包

  安裝包可以再Skywalking的官網(wǎng)下載,http://skywalking.apache.org/downloads/

  目前最新版本是8.0.1版本:

 

1698027688178_圖5.jpg

  下載好的安裝包:

1698027714818_圖6.jpg

  安裝OAP服務和WebUI

  安裝

  將下載好的安裝包解壓到Linux的某個目錄下:

tar xvf apache-skywalking-apm-es7-8.0.1.tar.gz

  然后對解壓好的文件夾重命名:

mv apache-skywalking-apm-es7 skywalking

  進入解壓好的目錄:

cd skywalking

  查看目錄結構:

1698027789068_圖7.jpg

  幾個關鍵的目錄:

  - agent:探針

  - bin:啟動腳本

  - config:配置文件

  - logs:日志

  - oap-libs:依賴

  - webapp:WebUI

  這里要修改config目錄中的application.yml文件,詳細配置見官網(wǎng):https://github.com/apache/skywalking/blob/v8.0.1/docs/en/setup/backend/backend-setup.md

  配置

  進入`config`目錄,修改`application.yml`,主要是把存儲方案從h2改為elasticsearch

  可以直接使用下面的配置:

cluster:
  selector: ${SW_CLUSTER:standalone}
  standalone:
core:
  selector: ${SW_CORE:default}
  default:
    role: ${SW_CORE_ROLE:Mixed} # Mixed/Receiver/Aggregator
    restHost: ${SW_CORE_REST_HOST:0.0.0.0}
    restPort: ${SW_CORE_REST_PORT:12800}
    restContextPath: ${SW_CORE_REST_CONTEXT_PATH:/}
    gRPCHost: ${SW_CORE_GRPC_HOST:0.0.0.0}
    gRPCPort: ${SW_CORE_GRPC_PORT:11800}
    gRPCSslEnabled: ${SW_CORE_GRPC_SSL_ENABLED:false}
    gRPCSslKeyPath: ${SW_CORE_GRPC_SSL_KEY_PATH:""}
    gRPCSslCertChainPath: ${SW_CORE_GRPC_SSL_CERT_CHAIN_PATH:""}
    gRPCSslTrustedCAPath: ${SW_CORE_GRPC_SSL_TRUSTED_CA_PATH:""}
    downsampling:
      - Hour
      - Day
      - Month
    # Set a timeout on metrics data. After the timeout has expired, the metrics data will automatically be deleted.
    enableDataKeeperExecutor: ${SW_CORE_ENABLE_DATA_KEEPER_EXECUTOR:true} # Turn it off then automatically metrics data delete will be close.
    dataKeeperExecutePeriod: ${SW_CORE_DATA_KEEPER_EXECUTE_PERIOD:5} # How often the data keeper executor runs periodically, unit is minute
    recordDataTTL: ${SW_CORE_RECORD_DATA_TTL:3} # Unit is day
    metricsDataTTL: ${SW_CORE_RECORD_DATA_TTL:7} # Unit is day
    # Cache metric data for 1 minute to reduce database queries, and if the OAP cluster changes within that minute,
    # the metrics may not be accurate within that minute.
    enableDatabaseSession: ${SW_CORE_ENABLE_DATABASE_SESSION:true}
    topNReportPeriod: ${SW_CORE_TOPN_REPORT_PERIOD:10} # top_n record worker report cycle, unit is minute
    # Extra model column are the column defined by in the codes, These columns of model are not required logically in aggregation or further query,
    # and it will cause more load for memory, network of OAP and storage.
    # But, being activated, user could see the name in the storage entities, which make users easier to use 3rd party tool, such as Kibana->ES, to query the data by themselves.
    activeExtraModelColumns: ${SW_CORE_ACTIVE_EXTRA_MODEL_COLUMNS:false}
    # The max length of service + instance names should be less than 200
    serviceNameMaxLength: ${SW_SERVICE_NAME_MAX_LENGTH:70}
    instanceNameMaxLength: ${SW_INSTANCE_NAME_MAX_LENGTH:70}
    # The max length of service + endpoint names should be less than 240
    endpointNameMaxLength: ${SW_ENDPOINT_NAME_MAX_LENGTH:150}
storage:
  selector: ${SW_STORAGE:elasticsearch7}
  elasticsearch7:
    nameSpace: ${SW_NAMESPACE:""}
    clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
    protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"}
    trustStorePath: ${SW_STORAGE_ES_SSL_JKS_PATH:""}
    trustStorePass: ${SW_STORAGE_ES_SSL_JKS_PASS:""}
    dayStep: ${SW_STORAGE_DAY_STEP:1} # Represent the number of days in the one minute/hour/day index.
    user: ${SW_ES_USER:""}
    password: ${SW_ES_PASSWORD:""}
    secretsManagementFile: ${SW_ES_SECRETS_MANAGEMENT_FILE:""} # Secrets management file in the properties format includes the username, password, which are managed by 3rd party tool.
    indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:1} # The index shards number is for store metrics data rather than basic segment record
    superDatasetIndexShardsFactor: ${SW_STORAGE_ES_SUPER_DATASET_INDEX_SHARDS_FACTOR:5} # Super data set has been defined in the codes, such as trace segments. This factor provides more shards for the super data set, shards number = indexShardsNumber * superDatasetIndexShardsFactor. Also, this factor effects Zipkin and Jaeger traces.
    indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}
    # Batch process setting, refer to https://www.elastic.co/guide/en/elasticsearch/client/java-api/5.5/java-docs-bulk-processor.html
    bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:1000} # Execute the bulk every 1000 requests
    flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} # flush the bulk every 10 seconds whatever the number of requests
    concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requests
    resultWindowMaxSize: ${SW_STORAGE_ES_QUERY_MAX_WINDOW_SIZE:10000}
    metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}
    segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}
    profileTaskQueryMaxSize: ${SW_STORAGE_ES_QUERY_PROFILE_TASK_SIZE:200}
    advanced: ${SW_STORAGE_ES_ADVANCED:""}
  h2:
    driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
    url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
    user: ${SW_STORAGE_H2_USER:sa}
    metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
receiver-sharing-server:
  selector: ${SW_RECEIVER_SHARING_SERVER:default}
  default:
    authentication: ${SW_AUTHENTICATION:""}
receiver-register:
  selector: ${SW_RECEIVER_REGISTER:default}
  default:

receiver-trace:
  selector: ${SW_RECEIVER_TRACE:default}
  default:
    sampleRate: ${SW_TRACE_SAMPLE_RATE:10000} # The sample rate precision is 1/10000. 10000 means 100% sample in default.
    slowDBAccessThreshold: ${SW_SLOW_DB_THRESHOLD:default:200,mongodb:100} # The slow database access thresholds. Unit ms.

receiver-jvm:
  selector: ${SW_RECEIVER_JVM:default}
  default:

receiver-clr:
  selector: ${SW_RECEIVER_CLR:default}
  default:

receiver-profile:
  selector: ${SW_RECEIVER_PROFILE:default}
  default:

service-mesh:
  selector: ${SW_SERVICE_MESH:default}
  default:

istio-telemetry:
  selector: ${SW_ISTIO_TELEMETRY:default}
  default:

envoy-metric:
  selector: ${SW_ENVOY_METRIC:default}
  default:
    acceptMetricsService: ${SW_ENVOY_METRIC_SERVICE:true}
    alsHTTPAnalysis: ${SW_ENVOY_METRIC_ALS_HTTP_ANALYSIS:""}

prometheus-fetcher:
  selector: ${SW_PROMETHEUS_FETCHER:default}
  default:
    active: ${SW_PROMETHEUS_FETCHER_ACTIVE:false}

receiver_zipkin:
  selector: ${SW_RECEIVER_ZIPKIN:-}
  default:
    host: ${SW_RECEIVER_ZIPKIN_HOST:0.0.0.0}
    port: ${SW_RECEIVER_ZIPKIN_PORT:9411}
    contextPath: ${SW_RECEIVER_ZIPKIN_CONTEXT_PATH:/}

receiver_jaeger:
  selector: ${SW_RECEIVER_JAEGER:-}
  default:
    gRPCHost: ${SW_RECEIVER_JAEGER_HOST:0.0.0.0}
    gRPCPort: ${SW_RECEIVER_JAEGER_PORT:14250}

query:
  selector: ${SW_QUERY:graphql}
  graphql:
    path: ${SW_QUERY_GRAPHQL_PATH:/graphql}

alarm:
  selector: ${SW_ALARM:default}
  default:

telemetry:
  selector: ${SW_TELEMETRY:none}
  none:
  prometheus:
    host: ${SW_TELEMETRY_PROMETHEUS_HOST:0.0.0.0}
    port: ${SW_TELEMETRY_PROMETHEUS_PORT:1234}

configuration:
  selector: ${SW_CONFIGURATION:none}
  none:
  grpc:
    host: ${SW_DCS_SERVER_HOST:""}
    port: ${SW_DCS_SERVER_PORT:80}
    clusterName: ${SW_DCS_CLUSTER_NAME:SkyWalking}
    period: ${SW_DCS_PERIOD:20}
  apollo:
    apolloMeta: ${SW_CONFIG_APOLLO:http://106.12.25.204:8080}
    apolloCluster: ${SW_CONFIG_APOLLO_CLUSTER:default}
    apolloEnv: ${SW_CONFIG_APOLLO_ENV:""}
    appId: ${SW_CONFIG_APOLLO_APP_ID:skywalking}
    period: ${SW_CONFIG_APOLLO_PERIOD:5}
  zookeeper:
    period: ${SW_CONFIG_ZK_PERIOD:60} # Unit seconds, sync period. Default fetch every 60 seconds.
    nameSpace: ${SW_CONFIG_ZK_NAMESPACE:/default}
    hostPort: ${SW_CONFIG_ZK_HOST_PORT:localhost:2181}
    # Retry Policy
    baseSleepTimeMs: ${SW_CONFIG_ZK_BASE_SLEEP_TIME_MS:1000} # initial amount of time to wait between retries
    maxRetries: ${SW_CONFIG_ZK_MAX_RETRIES:3} # max number of times to retry
  etcd:
    period: ${SW_CONFIG_ETCD_PERIOD:60} # Unit seconds, sync period. Default fetch every 60 seconds.
    group: ${SW_CONFIG_ETCD_GROUP:skywalking}
    serverAddr: ${SW_CONFIG_ETCD_SERVER_ADDR:localhost:2379}
    clusterName: ${SW_CONFIG_ETCD_CLUSTER_NAME:default}
  consul:
    # Consul host and ports, separated by comma, e.g. 1.2.3.4:8500,2.3.4.5:8500
    hostAndPorts: ${SW_CONFIG_CONSUL_HOST_AND_PORTS:1.2.3.4:8500}
    # Sync period in seconds. Defaults to 60 seconds.
    period: ${SW_CONFIG_CONSUL_PERIOD:1}
    # Consul aclToken
    aclToken: ${SW_CONFIG_CONSUL_ACL_TOKEN:""}

exporter:
  selector: ${SW_EXPORTER:-}
  grpc:
    targetHost: ${SW_EXPORTER_GRPC_HOST:127.0.0.1}
    targetPort: ${SW_EXPORTER_GRPC_PORT:9870}

  啟動

  要確保已經(jīng)啟動了elasticsearch,并且防火墻開放8080、11800、12800端口。

  進入`bin`目錄,執(zhí)行命令即可運行:

./startup.sh

  默認的UI端口是8080,可以訪問:http://192.168.150.101:8080

1698027891500_圖8.jpg

  部署微服務探針

  現(xiàn)在,Skywalking的服務端已經(jīng)啟動完成,我們還需要在微服務中加入服務探針,來收集數(shù)據(jù)。

  解壓

  首先,將課前資料給的壓縮包解壓

1698027907610_圖9.jpg

  將其中的`agent`解壓到某個目錄,不要出現(xiàn)中文,可以看到其結構如下:

1698027923455_圖10.jpg

  其中有一個`skywalking-agent.jar`就是一我們要用的探針。

  配置

  如果是運行一個jar包,可以在運行時輸入?yún)?shù)來指定探針:

java -jar xxx.jar -javaagent:C:/lesson/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=ly-registry -Dskywalking.collector.backend_service=192.168.150.101:11800

  本例中,我們用開發(fā)工具來運行和配置。

  使用IDEA開發(fā)工具打開一個你的項目,在IDEA工具中,選擇要修改的啟動項,點擊右鍵,選擇`Edit Configuration`:

1698027971277_圖11.jpg

  然后在彈出的窗口中,點擊`Environment`,選擇`VM options`后面對應的展開按鈕

1698027986847_圖12.jpg

  在展開的輸入框中,輸入下面的配置:

-javaagent:C:/lesson/skywalking-agent/skywalking-agent.jar
-Dskywalking.agent.service_name=ly-registry
-Dskywalking.collector.backend_service=192.168.150.101:11800

  注意:

  - `-javaagent:C:/lesson/skywalking-agent/skywalking-agent.jar`:配置的是skywalking-agent.jar這個包的位置,要修改成你自己存放的目錄

  - `-Dskywalking.agent.service_name=ly-registry`:是當前項目的名稱,需要分別修改為`ly-registry`、`ly-gateway`、`ly-item-service`

  - `-Dskywalking.collector.backend_service=192.168.150.101:11800`:是Skywalking的OPA服務地址,采用的是GRPC通信,因此端口是11800,不是8080

  啟動

  Skywalking的探針會在項目啟動前對class文件進行修改,完成探針植入,對業(yè)務代碼零侵入,所以我們只需要啟動項目,即可生效了。

  啟動項目,然后對項目中的的業(yè)務接口訪問,探針就開始工作了。

  WebUI界面

  訪問:http://192.168.150.101:8080可以看到統(tǒng)計數(shù)據(jù)已經(jīng)出來了:

1698028038787_圖13.jpg

  服務實例的性能監(jiān)控:

1698028055937_圖14.jpg

  服務拓撲圖:

1698028069444_圖15.jpg

1698028085477_圖16.jpg

  某次請求的鏈路追蹤信息:

1698028102457_圖17.jpg

  表格視圖:

1698028118169_圖18.jpg

  本文版權歸黑馬程序員Java培訓學院所有,歡迎轉載,轉載請注明作者出處。謝謝!

  作者:黑馬程序員Java培訓學院

  首發(fā):https://java.itheima.com

分享到:
在線咨詢 我要報名
和我們在線交談!