在大部分的微服務架構中,Nginx基本上是常用的存取層設施,所以我們希望請求ID從Nginx層進行校驗填充,並且列印在Nginx的請求日誌中。
閱讀提示:本文不提供鏈路追蹤的完整解決方案,只提供Nginx層對鏈路追蹤的支援方案!
微服務的誕生,解決了傳統單體應用的許多問題,如可維護性差、擴展性差和靈活性差等問題(粗粒比較)。微服務架構雖好,但同時也帶來了許多挑戰,其中 故障排查 就是其需要解決的挑戰之一。那麼,如何在很多個應用程式和實例中找到故障發生的根源呢?
基於以上需求,我們可以將每一筆交易在各個應用中產生的所有日誌,進行集中式收集與展示(但前提是你得有:日誌中心)。這樣很快就可以看出交易是在哪一步出來的故障。如果做得好,還可以直接進行二次開發與資料分析,將收集的日誌和出現的故障進行分析後,用圖形介面很直觀的進行展示。
例如,可以展示出微服務呼叫的拓樸圖,使用顏色進行區分故障(如常用紅:表示異常、綠:正常、黃:警告)。接著可以將常出現的故障或異常進行分類後做出友好型的展示(說白了就不用直接上堆疊),如:NullPointerException:則界面直接友好型的提示哪一行代碼拋了空指針,輸入參數是什麼……(這不是這篇的重點哈,廢話不多說了,後續有機會再詳細介紹)。
要做整個微服務架構的鏈路追踪,肯定是希望從交易進入微服務中心的第一個點就開始有一個全局的交易ID來關聯所有日誌(鏈路追踪,這麼一個ID肯定是不夠的,但這裡只介紹這個哈)。當然最理想的肯定是希望把前端的日誌(如操作日誌、資料流等)也規劃進行。
在大部分的微服務架構中,Nginx基本上是常用的存取層設施,所以我們希望請求ID從Nginx層進行校驗填充,並且印在Nginx的請求日誌中。這裡只提供三種方式來實現Nginx層的交易ID生產方式。
在1.11.0之前的版本,我們可以採用拼接的方式來組裝請求ID。參考配置如下:
<span class="hljs-section">server</span> { <span class="hljs-comment"># 定义$request_trace_id的值,在1.11.0之前,我们可以使用类似的方式声明</span> <span class="hljs-comment"># 只要能确保其值出现重复的可能性尽可能的小即可。 </span> <span class="hljs-attribute">set</span> <span class="hljs-variable">$request_trace_id</span> trace-id-<span class="hljs-variable">$pid</span>-<span class="hljs-variable">$connection</span>-<span class="hljs-variable">$bytes_sent</span>-<span class="hljs-variable">$msec</span>; <span class="hljs-attribute">location</span> / { <span class="hljs-comment"># ……</span> <span class="hljs-comment"># 将此trace_id传递给后端的server,通过header方式,此后我们既可以在环境中获取此header </span> <span class="hljs-attribute">proxy_set_header</span> X-Request-Id <span class="hljs-variable">$request_trace_id</span>; } }
參數說明:
- $pid:nginx worker進程號
- $connection:與upstream server連結id數
- $bytes_sent:發送位元組數
- $msec:當前時間,即此變數所取得的時間,包含秒、毫秒數(中間以.分割)
利用系統/dev/urandom 產生的隨機 UUID 。參考腳本如下:
<span class="hljs-comment">---</span> <span class="hljs-comment">--- UUID</span> <span class="hljs-comment">--- Created by lry.</span> <span class="hljs-comment">--- DateTime: 2018/2/25 下午7:38</span> <span class="hljs-comment">--- Describe: 用系统/dev/urandom生成的随机uuid</span> <span class="hljs-comment">---</span> <span class="hljs-keyword">local</span> template =<span class="hljs-string">"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"</span> <span class="hljs-keyword">local</span> d = <span class="hljs-built_in">io</span>.open(<span class="hljs-string">"/dev/urandom"</span>, <span class="hljs-string">"r"</span>):read(<span class="hljs-number">4</span>) <span class="hljs-built_in">math</span>.randomseed(<span class="hljs-built_in">os</span>.time() + d:byte(<span class="hljs-number">1</span>) + (d:byte(<span class="hljs-number">2</span>) * <span class="hljs-number">256</span>) + (d:byte(<span class="hljs-number">3</span>) * <span class="hljs-number">65536</span>) + (d:byte(<span class="hljs-number">4</span>) * <span class="hljs-number">4294967296</span>)) <span class="hljs-keyword">local</span> uuid=<span class="hljs-built_in">string</span>.gsub(template, <span class="hljs-string">"x"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(c)</span></span> <span class="hljs-keyword">local</span> v = (c == <span class="hljs-string">"x"</span>) <span class="hljs-keyword">and</span> <span class="hljs-built_in">math</span>.random(<span class="hljs-number">0</span>, <span class="hljs-number">0xf</span>) <span class="hljs-keyword">or</span> <span class="hljs-built_in">math</span>.random(<span class="hljs-number">8</span>, <span class="hljs-number">0xb</span>) <span class="hljs-keyword">return</span> <span class="hljs-built_in">string</span>.format(<span class="hljs-string">"%x"</span>, v) <span class="hljs-keyword">end</span>) <span class="hljs-keyword">return</span> uuid
Nginx在 1.11.0版本中就提供了内置变量 $request_id ,其原理就是生成32位的随机字符串,虽不能比拟UUID的概率,但32位的随机字符串的重复概率也是微不足道了,所以一般可视为UUID来使用即可。参考配置如下:
<span class="hljs-comment"># Nnginx代理默认会把header中参数的 "_" 下划线去掉,所以后台服务器后就获取不到带"_"线的参数名</span> <span class="hljs-attribute">underscores_<span class="hljs-keyword">in</span>_headers</span> <span class="hljs-literal">on</span>; <span class="hljs-comment"># 设定日志格式</span> <span class="hljs-attribute"><span class="hljs-built_in">log</span>_format</span> main \<span class="hljs-string">'<span class="hljs-variable">$remote_addr</span> - <span class="hljs-variable">$remote_user</span> [<span class="hljs-variable">$time_local</span>] "<span class="hljs-variable">$request</span>" \' \'<span class="hljs-variable">$status</span> <span class="hljs-variable">$body_bytes_sent</span> "<span class="hljs-variable">$http_referer</span>" <span class="hljs-variable">$upstream_http_request_id</span> \' \'"<span class="hljs-variable">$http_user_agent</span>" "<span class="hljs-variable">$http_x_forwarded_for</span>"\'; server { location / { <span class="hljs-comment"># 如果请求头中已有该参数,则获取即可;如果没有,则使用</span><span class="hljs-variable"><span class="hljs-comment">$request_id</span></span><span class="hljs-comment">进行填充</span> <span class="hljs-built_in">set</span> <span class="hljs-variable">$temp_request_id</span> <span class="hljs-variable">$http_x_request_id</span>; <span class="hljs-keyword">if</span> (<span class="hljs-variable">$temp_request_id</span> = "") { <span class="hljs-built_in">set</span> <span class="hljs-variable">$temp_request_id</span> <span class="hljs-variable">$request_id</span>; } <span class="hljs-comment"># 屏蔽掉原来的请求头参数</span> proxy_<span class="hljs-built_in">set</span>_header x_request_id ""; <span class="hljs-comment"># 设置向后转发的请求头参数</span> proxy_<span class="hljs-built_in">set</span>_header X-Request-Id <span class="hljs-variable">$temp_request_id</span>; } } </span>
生成交易ID的方式有很多种,但希望使用者结合自身实际情况进行合理取舍,而不要盲目的追求ID的唯一性、可读性和时序性等等。
比如,ID具有时序性虽然有一定的好处,但实际的架构根本没有去使用该时序性,则没必要花大量的精力和做出大量的开发,去实现一个有时序性的交易ID。又比如,觉得UUID可读性太差,从而花了很多成本去开发一个具有一定含义的交易ID(如前几位表示什么意思,多少位到多少位又表示什么意思之类的),开发出来后,实际架构根本没有去解读该ID的地方,则浪费了成本。
但也不是所有人都直接使用UUID就能满足的,比如我需要考虑日志的容量,则可以考虑适当缩减ID的长度(每个ID缩减10个字符串,每笔交易就可能少几百或几千个字符串,再往上规划,还是可以减少一些日志容量的)。
最后,如果有考虑想收集前端的日志的童鞋,建议交易ID就不要使用Long型,因为前端可能会有损失精度的问题。同时也建议使用 $request_id 来填充交易ID。
以上是微服務架構之Nginx連結追蹤的詳細內容。更多資訊請關注PHP中文網其他相關文章!

LinuxandWindowsManageMemoryDifferlyderduetheirdesignphilosophies.linuxusesovercommittingforbetterperforbetterformanceButriskSout-MemoryErrors,而WindowsEmploysdemplysdempagingandMemorycompressionCompressionForstanity and效率

Linux系統依靠防火牆來保護未經授權的網絡訪問。 這些軟件障礙控製網絡流量,允許基於預定義的規則來阻止數據包。 他們主要在網絡層操作,他們管理

確定Linux系統是台式機還是筆記本電腦對於系統優化至關重要。本指南概述了簡單的命令以識別您的系統類型。 hostnamectl命令:此命令提供了一種檢查系統機箱的簡潔方法

Linux服務器TCP/IP連接數限制調整指南 Linux系統常用於服務器和網絡應用,管理員經常會遇到TCP/IP連接數達到上限的問題,導致用戶連接錯誤。本文將指導您如何提升Linux系統中的最大TCP/IP連接數。 TCP/IP連接數理解 TCP/IP (傳輸控制協議/互聯網協議)是互聯網的基本通信協議。每個TCP連接都需要係統資源。當活動連接過多時,系統可能會拒絕新的連接或速度變慢。 通過增加允許的最大連接數,可以提高服務器性能並處理更多並髮用戶。 檢查當前Linux連接數限制 在更改設置之

SVG(可擴展的矢量圖形)文件是徽標和插圖的理想選擇,因為它們的可重複性而沒有質量損失。 但是,PNG(便攜式網絡圖形)格式通常可以更好地與網站和應用程序兼容。本指南d

Livecode:跨平台發展革命 LiveCode是一種編程語言,於1993年首次亮相,簡化了每個人的應用程序開發。 它的高級,類似英語的語法和動態鍵入使得可以輕鬆地創建強大的應用程序

本指南提供了一個分步過程,用於通過Linux命令行重置故障USB設備。 使用這些命令簡化了對無響應或斷開USB驅動器的故障排除。 步驟1:識別您的USB設備 首先,我

在Linux上暫時設置靜態IP地址對於網絡故障排除或特定的會話配置是無價的。 本指南詳細介紹瞭如何使用命令行工具來實現此目的,並指出更改並非跨重啟


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Dreamweaver CS6
視覺化網頁開發工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver Mac版
視覺化網頁開發工具