一個奇葩的線上問題,導致我排查了一天

昨天線上又出了個問題,花了一天的時間才找到原因,說起來原因其實特別的坑爹啊。

事情是這樣的,最近我們上線了一個刷新用戶 token 的功能,也就是 APP 里經常有的,只要你經常操作,就能讓你一直保持在線狀態,不用一直重新登錄,需求就是這麼一個並不複雜的需求,也很快的上線了。

但是上線之後發現了一個用戶在某段時間持續長達 15 天沒有調用過刷新 token 的介面,還一直保持在登錄狀態(默認 token 失效是 7 天),這個就很奇怪了。

由於我並不是主要的開發,我是負責協助調查原因。

根據開發的口述,我得到的資訊如下:

  1. 根據資料庫日誌發現,用戶在8月份只登錄了兩次,兩次時間間隔有 15 天之長,另外排除了日誌丟失的問題,登錄這個日誌是同步保存並且在一個事務內的,不存在丟失的可能。
  2. 根據 ELK 網關日誌發現,用戶在這 15 天之內,基本上每天都會使用 APP,而且都還是需要登錄的介面。

  1. 根據 ELK 用戶服務日誌發現,用戶並沒有在這段時間內刷新過 token,按照道理應該在 7 天后過期,但是卻持續了 15 天。

以上的情況,我基本上都看到了,也一一驗證過,確實情況就是這樣。

那麼,我們排查的方向也就確定到,是不是有其他的 BUG 導致用戶的 token 會續期的問題?按說如果是這樣的話,那麼這個問題應該早就存在很久了,不可能等到這個需求上線才出現,也從未看到過任何這方面問題的回饋。

於是,我篩查了一部分用戶的日誌,發現登陸其實都挺有規律的,大部分情況都會在 <=7 天的時間有一次登陸,超過 7 天的情況看日誌也發現是沒有介面調用的,大概說明了這個問題是沒有出現過的。

難道是這次的上線導致的 bug?

於是諮詢了 QA 相關的測試情況以及開發提供的最近線上調用的日誌和情況來看,沒有什麼問題。

於是,我還特意去翻看了一遍程式碼,擔心有 BUG 導致給 token 續期了,然而排查後有沒有發現問題。

至此,排查好像陷入了僵局,於是只能從其他方面找思路。

我詢問了關於整個業務的調用鏈路,簡單來說就是用戶登錄的時候去請求 token,然後保存下來,以後每次請求的時候都帶上 token,然後鑒權的服務會去校驗 token 的有效性。

那麼,我不禁懷疑,難道鑒權的服務存在什麼問題???

於是又苦哈哈地排查了一遍鑒權服務的程式碼,發現程式碼寫的非常垃圾,token 的保存寫的到處都是,得有10幾個調用的地方。

通過 CAT 排查了一遍這些介面,發現其實大部分的介面最近一個月都沒有調用,和開發也確認了一下,這些介面基本都是老介面,已經沒有用了。

只有一個有存在調用的地方,也就是我們現在用的鑒權,這個地方只是簡單的去 redis 中判斷一下 token 是不是存在,在本地和測試環境中也去驗證了一把,並沒有發現問題。

OK,到此為止,時間也已經到了下午了,包括我在內的幾個排查人員已經快要炸了,這個問題已經找了快一天了,沒有發現任何問題,整個事情也就陷入了停滯狀態。

我默默地點了根煙,你還別說,小蘇還真是好抽的很(友情提醒,抽煙有害身體健康)。

我不禁想到以前 leader 說,我以前他么就不抽煙,然後組裡其他幾個人每次查問題查不到原因,就跑出去抽煙,結果一回來他們說問題找到了,於是我不得不也抽煙。。。

所以怎麼說,抽煙能給人帶來思路啊。

我不禁想到一個問題,他們說的只是他們說的,雖然我看了他們給我的演示,但是,我除了看到了用戶的登錄日誌,和他們給我看到的網關日誌、服務調用的日誌之外,我其實並沒有去自己去驗證他們的說法。

於是,我先從資料庫查看了登錄日誌,發現這個確實沒問題,程式碼驗證過,確實在登錄的事務之內,雖然這個程式碼寫的很垃圾,框了整個登錄邏輯,但是這個事務這時候缺他么額外的保證了這個日誌的存在的必要性!

我接著看網關日誌,發現也沒什麼問題,用戶的鑒權介面基本在一直調用,但是在7天之後也都通過了,並沒有提示 token 失效等情況。

於是我再接著看服務本身的調用日誌,之前他們給我看的時候,就是這樣一個結果,根據日誌資訊和用戶 ID 沒有找到日誌,因此排除了用戶調用過刷新 token 介面的情況。

這裡我隱隱感覺到不對勁,於是,我換了一個搜索方式,搜用戶的設備資訊,不搜用戶 ID!!!

結果尼瑪出現了!!!搜索到了結果,用戶在中間調用過一次刷新 token,看了下時間,第一次登陸8月8號,8月23號又登陸了一次,15號刷新了一次,時間剛好吻合,7天!

事情到這裡也基本上真相大白了,並不是有什麼雞毛的 BUG,純粹就是我相信了他們的排查結果並且沒有去驗證!在錯誤的排查道路上越走越遠了我!

真尼瑪是炸裂!

OK,到這裡不禁要想,為什麼用用戶 ID 搜不到結果?我把結果告訴開發的時候,他也驚呆了,他說我搜其他用戶 ID 可以搜到啊,說完還給我演示了一下。

我就測試了一下,發現確實可以,進一步測試了幾個用戶 ID,發現有的能搜到,有的不能搜到,這有點奇怪了。

仔細看到了一下我們的 token,發現 token.123.456bdf(中間的是用戶ID)這樣搜是不搜不到的,token.456.bde123這樣能搜到。

這應該是分詞的問題了,數字連在一起被當做一個字元串分詞了,所以存在有的能搜索到,有的不能搜索到,測試了一下發現情況確實是這樣。

我們可以自己測試一下 ELK 的分詞效果,進入首頁,然後選擇 ES API 交互。

驗證一下我們的猜測是不是因為分詞的問題導致的,默認應該是標準分詞,analyzer 選擇 standard,可以看到輸出結果確實是OK的。

再換一個字元串,tokentest 前加上一點數字,分詞的結果也確實如我們猜測的那樣。

解決方案的話有兩個,第一個只能換一個分詞器了,比如我們如果用pattern正則分詞器就可以達到我們想要的效果,但是用啥分詞這個我們說了不算。

第二個方法其實可以換一個搜索方式,比如message: "*token*" and message:*123456*這樣也能搜索到,只是你平時怎麼會這樣用呢,對吧。

總結一下,我們平時在排查問題的過程中,一定要自己動手,不要輕易相信別人說的情況,大膽假設,小心求證,方得善果。