Elastic:應用程序性能監控/管理(APM)實踐


在今天的文章里,我們將介紹Elastic的一個重要的應用:應用程序性能管理(Application Performance Monitoring/Management),簡稱APM。那么到底什么是APM呢?

隨着時代的發展,我們的IT架構越來越復雜,比如:

我們系統的服務器越來越多,而且更多的設備都部署在雲端。復雜的系統甚至有成千個微服務及架構所組成,那么我們的業務請求可能需要一個或更多的服務共同來完成。那么現在的問題是,如果我們的請求變得很慢,我們想知道到底是哪個環節出現問題了呢?經驗豐富的程序員或者系統設計者,可能從一些log里找到答案。可是當我們的log變得非常大的時候,而且我們的接口也越來越多時,這個時候,也許我們也無能為力。

當我們在設計頁面或者請求時,經常會遇到上面的這種等待的情況。可能有個別的工具能有效地解決部分的問題,但是如何能從整個的系統里來完成這種問題的定位及分析。Elastic推出的APM解決方案可以完美地解決這些問題。為我們的系統設計者或程序員提供了一個快速定位的方法。

APM 到底是什么呢?

我們先來看一下如下的這個圖:

如上圖所示,在不同時刻我們請求時,我們發現為什么在17:36:30發生的一個請求需要花將近8秒的時間,而另外在17:36:30分發生的一個請求卻返回一個錯誤的代碼?

Elastic APM方案是世界上第一個開源的APM 解決方案:

  • APM記錄數據庫查詢,外部HTTP請求以及對應用程序的請求期間發生的其他緩慢操作的跟蹤
    • 很容易讓程序員看到應用在運行時各個部分所花的時間
  • 它收集未處理的錯誤和異常
    • 很容讓程序員調試錯誤
  • 在客戶面對性能瓶頸和錯誤之前先定位到問題所在
  • 提高開發團隊的生產力

APM適用於Elastic Stack的位置

APM如何把數據存於Elasticsearch中,並提供分析呢?我們看一下如下的架構圖:

如上圖所示,我們看到一個最典型的APM架構圖:

  • 我們需要架設一台專門的APM服務器,雖然也可以和Elastic Stack的其它服務器處於同一台服務器中
  • AMP agent專門收集數據並發送數據到APM服務器中。這里的APM agents包含:

  • APM服務器把數據發送到Elasticsearch中,並進行數據分析
  • Kibana可以幫我們把數據進行展示並顯示在Dashboard之中

總體來說,APM數據僅僅是另外Elasticsearch索引。在Kibana中已經有一個現成的APM應用可以被我們所使用。我們也可以根據需求自己定制自己的Dashboard。APM可以完美地結合機器學習和告警。

APM術語

  • Service: 在apm agent配置中進行設置,以將特定的apm agent組標識為單個服務,這是一種邏輯上標識一組事務的方法
  • Transaction: 組成一個服務的請求和響應,例如 登錄api調用,每個調用由單獨的span組成。
  • Span: 事務中的單個事件,例如方法調用,數據庫查詢或緩存插入或檢索,即需要花費時間才能完成的任何事件。
  • Erorrs:具有匹配的異常或日志消息的異常組

它們之間的關系可以用如下的圖來表示:

分布式tracing:

例子

在今天的練習中,我們將以Java Spring boot為例來展示如何使用Elastic APM。

下載Spring boot代碼

首先,我們在terminal中打入如下的命令:

git clone https://github.com/liu-xiao-guo/elastic-apm-demo

上面的一個例子是一個簡單的Spring boot應用。它有一下的幾個特點:

  • 它可以REST接口訪問MySQL的數據庫進行添加數據,請求數據
  • 它可以通過REST接口進行訪問百度天氣接口來獲得天氣數據

下面是它的部分代碼:

    	@PostMapping(path="/add") // Map ONLY POST Requests
    	public @ResponseBody String addNewUser (@RequestParam String name
    			, @RequestParam String email) {
    		// @ResponseBody means the returned String is the response, not a view name
    		// @RequestParam means it is a parameter from the GET or POST request
     
    		User n = new User();
    		n.setName(name);
    		n.setEmail(email);
    		userRepository.save(n);
    		return "Saved";
    	}
     
    	@GetMapping(path="/all")
    	public @ResponseBody Iterable<User> getAllUsers() {
    		// This returns a JSON or XML with the users
    		return userRepository.findAll();
    	}
     
    	@GetMapping(path="/weather")
    	public @ResponseBody String getBaiduWeather() throws InterruptedException {
    		// Add some random delays before getting the info
    		double delay = Math.random() * 10;
    		System.out.println("delay: " + delay);
    		TimeUnit.SECONDS.sleep((long)delay);
     
    		String weather = getWeatherInform("北京");
     
    		return weather;
    	}

在獲得天氣(weather)的接口中,我故意加入了一下隨機數的延遲,這樣來模擬每一次請求的時間是不同的。

我們可以在應用的根目錄下打入如下的命令:

./mvnw clean package

這樣它將會在當前目錄下的target子目錄下生產一個叫做accessing-data-mysql-0.0.1-SNAPSHOT.jar的文件。

    $ ls ./target/accessing-data-mysql-0.0.1-SNAPSHOT.jar
    ./target/accessing-data-mysql-0.0.1-SNAPSHOT.jar

我們可以把這個文件拷入到我們想要的任何一個目錄中。針對我的情況,我把它拷入到我的home目錄下的data/apm目錄中。

    $ pwd
    /Users/liuxg/data/apm
    liuxg-2:apm liuxg$ ls accessing-data-mysql-0.0.1-SNAPSHOT.jar
    accessing-data-mysql-0.0.1-SNAPSHOT.jar

安裝MySQL

我們可以按照文檔的需求來安裝我們的MySQL。我們在一個terminal中打入如下的命令:

mysql -uroot -p

我們打入root用戶的密碼進入到MySQL之中。為了創建一個數據庫,我們在MySQL的prompt中打入如下的命令:

    mysql> create database db_example; -- Creates the new database
    mysql> create user 'springuser'@'%' identified by 'ThePassword'; -- Creates the user
    mysql> grant all on db_example.* to 'springuser'@'%'; -- Gives all privileges to the new user on the newly created database

上面的命令創建了一個叫做db_example的數據庫。同時,它也創建了一個叫做springuser的用戶及其密碼ThePassword。我們可以通過Navicat工具來查看:

運行Elastic Stack

安裝及運行我們的Elasticsearch及Kibana。我們打開我們的Kibana界面,並點擊左上角的部分:

然后,我們按照上面的步驟一步一步地進行安裝:

上面的步驟非常詳細。對於APM agent的選擇來講,因為我們是Java應用,所以我們選擇Java agent。我們下載相應的agent jar文件,並存放於我們上面放置spring boot的jar文件所處的文件夾。針對我的情況是home目錄下的data/apm。

    $ pwd
    /Users/liuxg/data/apm
    liuxg-2:apm liuxg$ ls elastic-apm-agent-1.10.0.jar 
    elastic-apm-agent-1.10.0.jar

在這個時候,我們可以開始運行我們的Spring Java應用了。我們可以通過如下的命令來運行:

    java -javaagent:./elastic-apm-agent-1.10.0.jar \
         -Delastic.apm.service_name=sample_apm \
         -Delastic.apm.server_url=http://localhost:8200 \
         -Delastic.apm.secret_token= \
         -Delastic.apm.application_packages=accessing-data-mysql \
         -jar accessing-data-mysql-0.0.1-SNAPSHOT.jar

注意:這里的sample_apm是我給取的一個服務名稱。你可以根據自己的需求取一個獨特的名字。如果你不想這么麻煩,你可以在當前的目錄下生產一個叫做elasticapm.properties的文件。它的內容如下:

    service_name=sample_apm
    application_packages=accessing-data-mysql
    server_url=http://localhost:8200

那么我們可以通過如下的命令來運行:

    java -javaagent:./elastic-apm-agent-1.10.0.jar \
         -Delastic.apm.secret_token= \
         -jar accessing-data-mysql-0.0.1-SNAPSHOT.jar

等我們的Spring Boot應用完全起來后,我們點擊Kibana中的“Check agent status”按鈕。這個時候可能顯示沒有任何的數據。我們可以打開我們的瀏覽器,並在瀏覽器的地址欄中輸入如下的地址:

我們可以看到我們得到了一下天氣的數據信息。那么這個時候我們可以在Agent status中看到信息:

啟動APM應用

如果你已經運行到這里,那么你基本上已經把整個的環境運行起來了。我們可以在terminal中打入如下的命令:

curl localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com

上面的應用是向我們的數據中寫入一條記錄。

curl 'localhost:8080/demo/all'

運行上面的命令可以展示已經輸入的所有的記錄

curl 'localhost:8080/demo/weather'

運行上面的命令可以獲得百度天氣API接口所帶給我們的天氣信息。

上面的所有的信息我們都可以在瀏覽器中的地址欄中輸入。

點擊Kibana中的APM應用圖標:

在上面我們可以看到應用的四個接口的統計情況。

我們在這個APM應用的dashboard上可以看到我們所有的API的調用情況。比如:

因為在我的應用中,我故意加入了一些延遲,所以導致我們的整個getBaiduWeather的請求時間為9.157秒才完成,而api.map.baidu.com的時間只有149ms。

到這里我的講解就完成了。剩下的留給大家自己去挖掘哈!

參考:
【1】Accessing data with MySQL(https://spring.io/guides/gs/accessing-data-mysql/)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM