我在神策做研发 | 与客户难题“对抗”的百余天
?
?
對于每一個客戶的問題,不管大小,都需要跟進追蹤到底,以獲得最佳的答案。
一個問題一個坑,留了坑,前路必將荊棘叢生;填了坑,前路即是坦途。這是神策人的做事態度和行事準則,也幫助我樹立了積極的人生觀。
如果同行也正在經受類似問題的困擾,希望同行可以通過這篇文章,在排查過程中能夠獲得一點啟發。
刷量?客戶反饋異常 IP 發送大量重復數據
從今年 2 月份起,我陸續收到客戶反饋:Web JS SDK 短時間內上報了大量重復的數據到神策分析,從而影響了客戶的分析、決策和制定運營計劃。對于這種情況我們通常稱之為 “刷量”。什么是刷量?
圖 1? 刷量表現—按天
圖 2? 刷量表現—按分鐘
用戶所反饋的現象和刷量一致,有幾個異常 IP 短時間內密集發送 Web 端重復數據入庫。一個 IP 一天發送的重復數據甚至達到了幾十萬、上百萬條,這顯然不是一個正常用戶產生的行為數據。
我們查看了刷量時的用戶行為序列,如下圖,可以看到事件是重復循環觸發的,時間間隔在幾十毫秒。
圖 3? 刷量發生時的用戶行為序列
針對此問題的反饋,我們進行了快速排查及提供初步解決方案。
當時的排查思路:
一,會不會是客戶代碼 bug 導致重復觸發事件?
通過協調運維幫忙查詢事件日志,證明這些重復事件的 _track_id(Web JS SDK 對發送數據生成的隨機數,每條采集和發送的數據都會有自己獨特的 _track_id) 是一樣的。從這個方面看,基本排除了是客戶代碼 bug 導致的,因為即使是代碼重復觸發的事件,_track_id 是不會重復的。
二,會不會是別人惡意獲取了神策的數據采集請求和數據體,使用工具或者腳本偽造請求,灌注臟數據到神策分析服務器?
Web JS SDK 采集的數據,默認使用 image 方式發送數據,GET 請求的數據接收地址和數據體都包含在請求的 URL 中,如圖所示:
圖 4? Web JS SDK 的數據發送
只要復制該 Request URL 直接在瀏覽器地址欄訪問,或者使用腳本訪問,就會有一條一模一樣的數據入庫。這也符合? _track_id 重復的情況,而且可以集中產生大量的請求,實現灌注臟數據。在本地使用腳本模擬,也能夠復現出來數據刷量的情況。
因此,推測的結論是:有人從集成了 Web JS SDK 的頁面上,截取了發送的數據請求,并通過腳本灌注臟數據進入神策分析。
根據這一結論,給客戶的方案是:將 Web JS SDK 的數據發送方式從 image 改成 ajax,這樣請求就會從 GET 變成 POST,在一定程度上避免將整個請求暴露在 URL 上;將出現過刷量的 IP 增加到后端的防火墻黑名單中。
問題又現!存疑,再深入排查
但是,似乎并沒有解決問題。在接下來的一個月,依舊陸續收到刷量的情況反饋。
我每天值班也都膽戰心驚,只要有客戶反饋刷量的情況,心里都咯噔一下:如果是有人惡意刷量,那么持續刷的動作有點說不通,是否有其他原因導致……問號一直懸在那里,始終無法說服自己。
我們內部組織 Web JS SDK 開發人員來集中開會討論,當時判斷刷量的可能原因:Web JS SDK 的 bug 導致?有人惡意攻擊,灌注的臟數據導致?后端服務中的 bug 導致的重復讀取數據導致?
為了驗證我們的推測,申請了一個客戶被刷量的環境查看,判斷不是 Web JS SDK 和后端服務的 bug ,目前的方向也只剩下是有人惡意攻擊了。Web JS SDK 在前端針對這種情況,沒有什么方法阻止,寄希望于后端可以將這樣的刷量數據去重。
由于 Web 端的數據入庫后,默認使用服務器時間,而服務端的去重邏輯是根據? track_id、time 等一起去重。像這樣的刷量數據入庫,雖然 track_id 一致,但是 time 相差只有幾十毫秒,因此無法去重。為了解決這一問題,可以在后端對于 Web 端數據的去重邏輯中將 time 字段去除,這樣就可以對刷量數據進行去重了。
不過,這只是一個臨時解決方案,且該方案只針對集群版有效,有一定的局限性。另外,這種方案屬于出現了刷量后的被動處理。
“用力啊!”
對于此問題,書記也一直懷疑,每天見我必問:“有進展嗎?用力啊!”
由于并沒有找到確定的原因,我在網上查到 image 請求死循環的資料,如下圖所示:
圖 5? image 請求死循環資料
于是我查看 Web JS SDK 源碼,發現已經對 image 請求的 onerror 做了 null 賦值處理,不會出現死循環現象。有點失落,這個方向也是不對的。
場景難以復現,多次轉機出現卻屢陷僵局
終于,轉折出現了。當我與被刷量客戶的技術做深入溝通時,有了一個重大發現。
4 月的某天,客戶拿到注冊用戶的手機號,通過技術人員聯系到這個用戶。發現用戶是正常操作,只是使用了某瀏覽器訪問頁面。當時,遠程客戶電腦進行操作,發現如果關閉瀏覽器后就會停止刷數據,瀏覽器處于開啟狀態就會一直刷數據。另外,發現用戶的瀏覽器版本比較老,讓其升級到最新的瀏覽器后,依然能夠出現刷數據的情況。同時,在訪問頁面時頁面會有卡頓情況,風扇也轉的特別厲害。另外,同一時刻該用戶對客戶自己頁面的一個水印圖片訪問量也很大,達到了 21.4 萬次。但是,對神策的 sa.gif 訪問量更多,達到 255.4 萬次。
不過當客戶的技術在自己電腦上模擬的時候,無法復現這個問題。查看當前穩定版的 M 瀏覽器內核為 Chrome 78.0.3904.108。通過這個發現,我去查看其他客戶的最近刷量數據,均發現其 UA 是 Chrome 78.0.3904.108, 指向 M 瀏覽器。通過以上線索推論:刷量問題很可能不是人為惡意攻擊,而是 M 瀏覽器訪問針對 image 數據請求可能有無限循環的 bug 導致的。
按照客戶提供的線索,我反向查看了下:以該內核版本為篩選條件,發現出現刷量的那天,有近 5300 個用戶使用該內核版本訪問了頁面,而出現刷量的情況只有 1~2 個用戶。從這方面看,刷量似乎不是必現的。本地使用多臺電腦,測試 M 瀏覽器均沒有能夠復現,問題似乎又陷入了僵局。
再換一條路,基于 M 瀏覽器的問題判斷,我當天我在瀏覽器社區留言,希望可以從瀏覽器的工作人員那里可以獲得答復和幫助,如圖所示。
圖 6? 留貼瀏覽器社區
工作人員通過 QQ 聯系了我,并與我溝通了基本情況。由于他們沒有受理過類似問題,希望我提供復現的頁面,但是我這邊沒有復現的頁面。因此,這個方向的路也堵住了。
感恩信任!與「客戶的用戶」的多次遠程、面基……
在走投無路時,幾經輾轉,為復現場景,我再次聯系客戶的技術人員,希望能夠聯系到之前兩位用戶。經過客戶的提前溝通,以及一系列的保密協議簽署后,最終提供兩位用戶的聯系方式。
起初我幾次聯系,都沒有能夠打通電話。而此時,刷量問題愈演愈烈。因為線索只剩下這一條了,我就硬著頭皮繼續打電話,終于還是撥通了。
在此很感激兩位用戶的信任。第一位用戶幫忙安裝了 TeamViewer,并提供了遠程。可惜的是這一次沒有復現刷量的情況。
不能放棄,繼續聯系另一位用戶。由于是上班時間,另一位用戶電腦在家且不方便配合,約了周末在家配合我遠程:當打開他電腦上的瀏覽器并訪問客戶的頁面,用戶反饋電腦風扇開始響起來了。我打開任務管理器,發現其 M 瀏覽器訪問客戶網頁的 CPU 占比很高,如圖所示。
圖 7? 刷量時的任務管理器
同時從神策分析看,這個時候該機器在進行刷量,如圖所示:
圖 8? 刷量時的監控平臺
但是通過控制臺,并沒有發現大量數據刷量的請求,神策的 sa.gif 發送數據請求都是正常的,如圖所示。
圖 9 ?刷量時的控制臺信息
反反復復檢查了幾遍,沒有發現其他異常情況和原因。我只好斷了遠程,并嘗試和用戶約了下一次遠程查看。同時,試探了一下:如果遠程查看還是沒有發現問題,是否可以面基,直接由北京的同事操作和查看其電腦(由于我在合肥辦公),沒想到客戶居然真的同意了!
由于也占用了他比較長的時間,我這邊給他發了個 100 元紅包表示感謝(感謝書記給我報銷)。
結束客戶的遠程之后,和根哥溝通了第一次遠程的情況。根哥給了關鍵性的建議:可以查看下是不是電腦防火墻或者瀏覽器插件導致的。
因此,我與用戶約了周一中午再次遠程,該用戶將電腦背到公司,通過午休時間給我遠程查看。
三行代碼解決問題,瀏覽器也同步修復自身 BUG
中午我沒有休息,這次遠程,依然復現了問題。我從瀏覽器插件檢查,發現了一個可疑的插件:圖片下載插件,這個插件和之前發現的針對 sa.gif 圖片請求的刷量有一些重合之處。趕快測試下,果然有了突破。
當我禁止該插件時,CPU 降下來了,同時測試后端數據入庫也停止了刷量情況。反復測試后,驗證了確實是該插件導致的。
結束遠程后,我在本地使用機器測試,也能穩定的復現刷量的情況。在群里我同步了該插件的情況,其他同事也幫忙測試。同時,經過進一步的測試,通過打開插件的控制臺,發現了插件的確在重復不斷地發送圖片請求。
查看該插件,發現是該瀏覽器的應用市場中的一款常用的圖片下載擴展應用。應該是使用 Chrome 內核的時候,同時帶過來的,通過查看 Chrome 應用商店也發現了該插件。
在 Chrome 中安裝該擴展應用時,也復現了刷量的情況。由于 Chrome 商店國內訪問很少,所以少有用戶能夠直接下載該擴展使用。而 M 瀏覽器非常方便的提供了該應用的下載和安裝,且屬于圖片下載類擴展的前幾名擴展,如圖所示:
圖 10? 圖片下載類擴展排名
至此,刷量的原因總算是水落石出了。
同事想爺本地測試也驗證了刷量情況,并將插件源碼獲取到后,發給大家測試。基于想爺提供的源碼,我從網上查閱、學習插件開發和調試的方法后,在本地調試插件。開啟插件的調試模式,在插件的控制臺中,呈現了快速大量的重復 image 請求發送出去。調試插件代碼發現,該插件通過瀏覽器提供的 API 攔截瀏覽器的 image 請求后,又重新創建一個新的圖片請求去下載圖片。致命的是,該循環沒有加限制條件,這個新的圖片請求通過瀏覽器發送出去后,再次被攔截,又創建一個新的圖片請求。
研發大康哥通過調試該插件代碼,給出建議,只要補充三行代碼就可以解決該問題,如下圖所示:
圖 11? 插件優化代碼
根哥提出了幾個解決方案:
1. 在 SDK 中是否可以檢測到該插件,含有該插件的環境將發送方式變更為 ajax 方式;
2. 聯系 M 瀏覽器,反饋該問題插件,希望其可以安排對插件的檢測和下架;
3. 聯系插件作者,反饋問題,希望可以修復掉問題代碼,發布新版。
大康哥研究了一下:由于瀏覽器的限制,在頁面中無法查看這類擴展插件的列表。因此,無法在 Web JS SDK 集成時,從頁面的環境中查看當前瀏覽器是否集成了該插件,從而自動將數據的發送方式從 image 更改為 ajax。我這邊也從插件聲明的變量和靜態資源入手,嘗試了很多辦法,也沒有能夠在頁面的 SDK 上捕捉插件的變量或者靜態資源。至此,寄希望于 SDK 主動識別插件的方案走不通了。
大約在 6 月 8 日,我再次聯系瀏覽器工作人員,與之詳細反饋了插件情況。工作人員給了我一個 M 瀏覽器插件組的郵箱,讓我將詳細情況通過郵件的方式發給該部門,然后在 1 到 2 個工作日會有工作人員聯系我。此時,再去 M 瀏覽器的應用市場,將該插件截圖一下作為郵件內容發送出去,卻意外發現了一個驚喜,該插件已經做了升級。當前版本從 1.2.3 變成了 2.2.0 版本,同時去 Chrome 應用商店查看,里面該插件已經升級到 2.2.0 了。
安裝調試該插件代碼,發現已經將 bug 修復(此處與大康哥之前提出的修復代碼基本一致),代碼如下圖所示。
圖 12? 新版插件源碼
經過測試后,確實不會再出現刷量的情況了。同時,在隨后的值班過程中,也發現刷量問題出現的情況大幅減少。
除了解決客戶的問題,還能夠幫 M 瀏覽器暴露了插件問題,定位了有插件的用戶風扇狂轉和 CPU 飆升的問題原因,對我們來說,也是很開心的。
那些費力「不討好」的事情
在這個解決“刷量”的案例中,牽涉人員眾多,包括客戶、客戶的用戶、瀏覽器工作人員、第三方插件作者,還有神策各地同學,5 方的努力與協作,缺一不可。采用的手段也非常規,比如 SDK 技術顧問給「客戶的用戶」發紅包,再如 SDK 技術顧問通過網絡給 M 瀏覽器工作人員留言……
有外部人評價,我們在單個客戶上的付出,有時候會顯得“不劃算”,畢竟問題的本身不在神策。但對神策來說,這是難而正確的事,客戶的員工都看在眼里,我們不辜負客戶的信任,客戶問題無小事,始終 All In!
類似這種,我們幫客戶解決的『非分內』的問題,還有很多:
-
某公有云虛擬機性能下降導致神策系統運行慢,某公有云拒認,我們寫程序給出證據,某公有云遷移機器解決問題。
-
某客戶物理機磁盤硬件故障,供應商拒認,我們協助客戶證明,后來供應商承認并更換磁盤。
-
某客戶底層網絡 bug 影響神策業務,客戶內部部門不認可,我們寫程序證明,客戶表示 bug 修不了,被迫繞過。
-
某公用云虛擬機故障導致指令集不支持,某公有云拒認,我們寫程序證明,某公用云解決并上門道歉……
最后附上某位朋友送的一面錦旗。
其實,哪有什么「料 bug 如神」,只不過在每個問題被解決的背后,都付出了超常規的努力。
???
【更多內容】
-
神策軍 | 成長中的成都研發中心
-
神策面試官的修煉之道,選對人與吸引人 | 神策軍
-
神策軍 | 我有一本書,你拿思想來換
?
總結
以上是生活随笔為你收集整理的我在神策做研发 | 与客户难题“对抗”的百余天的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安信证券王环:安信证券数据中台建设历程
- 下一篇: 八城联动 丨 神策 2020 数据驱动用