JVM進階(七)——從GC日志分析堆內存
737
2025-04-01
前言
論文數據需要,需要實現從服務器日志中提取出用戶的特定交互行為信息。日志內容如下:? 自己需要獲取“請求數據包一行的信息”及“OUTSTR”下一行的信息。
思路
考慮使用正則表達式提取特定信息。
示例代碼:
Pattern pattern = Pattern.compile("請求數據包信息:\"(.+?)\""); Matcher matcher = pattern.matcher("請求數據包信息:\"index.html\""); if(matcher.find()) System.out.println(matcher.group(1));
考慮到日志中數據格式特點,利用上述方式并不可行。不過還是應該考慮使用正則解決以上問題。
初步處理后的文檔內容如下:
分析以上信息,需要進一步進行處理,將每個用戶的信息進行單獨抽取并存入到數據庫中。 作為實驗,先單獨獲取一用戶的數據。但是由于服務端返回數據無任何用戶標識,而且返回信息無任何交易標識,仍需添加。需要對日志做進一步的處理操作。添加信息如下:
通過將json格式的字符串轉換為json對象。并獲取到指定信息,如下所示:
為了提取出每個用戶的交互序列,實現方法如下:將日志中的交互序列按照用戶ID分別建立相應的文件夾。將同一用戶的請求與輸出信息輸出到同一用戶ID的文件內。內容如下:
文件內容如下:
通過分析分類后的文件內容,可以發現,由于存在某些耗時交易,故會出現多個請求、輸出交叉顯示的情況。
針對這種情況,在服務端返回信息中加入了uid,tx_code信息,如下所示:
那么就需要將服務端返回信息與請求信息進行配對操作。
考慮到交易的混合,服務端返回信息的混合,必須假設一種理想情況之下的處理。否則,處理起來過于費勁。
前提:客戶端的請求與服務端的響應按照線性順序出現,一一對應。
Ti、To到底存放什么類型的數據?Json中的key還是json對象?
只是單純存儲key的話,Ti、To基本上毫無用處,無法完成基于內容的行為預測與預警。
存儲json對象的話,數據量會非常龐大,應給與調整。到底應該進行怎樣的數據調整?只提取“重點信息”。例如交易金額,藥品種類。
還是應該結合系統說明文檔來做,將事件的輸入、輸出自動添加進(重點考慮輸入輸出內容)。
這樣問題的思路就很清晰了。
考慮將交易時間寫入數據表中,便于得出交易序列。同時可考慮將時間因素添加進去,做服務推薦(協同過濾,加入時間維度)。例如:在什么時間購買了什么藥品,可得出在這一時間段內該用戶易的某種疾病的推測。
日志信息的篩選:對于用戶行為序列中只存在一個事件的情況可考慮忽略不計。對于分析用戶的習慣無用。
獲取到指定信息后,需要將其存入數據庫中。數據表內容如下:
1.靜態屬性表(lab_static_attribute)
表名:lab_static_attribute
主鍵:uid,login_time,out_time,last_time
字段名
中文名
類型
備注
uid
用戶ID
Varchar(11)
uid
login_time
登陸時間
Varchar(1)
0 ??24:00-1:00
1 ??1:00-2:00
2 ??2:00-3:00
.
.
23 ?23:00-24:00
out_time
登出時間
Varchar(1)
0 ??24:00-1:00
1 ??1:00-2:00
2 ??2:00-3:00
.
.
23 ?23:00-24:00
last_time
在線時長
Int(3)
以秒為單位
2.動態序列表(lab_dynamic_order)
表名:lab_dynamic_order
主鍵:uid,tid,t_next
字段名
中文名
類型
備注
uid
用戶ID
Varchar(11)
uid
tid
事務ID
Varchar(4)
ti
輸入參數
Varchar(50)
tout
輸出結果
Varchar(50)
t_next
路由下一跳
Varchar(4)
下一個可執行路由
weight
路由權重
Int(3)
每條路由之間的權重
t_time
交易時間
Varchar(19)
接下來的工作就是建立數據庫,并實現數據庫的操作。
好長時間不涉及到數據庫的操作了,發覺自己已經變得生疏了。還得拾起來啊。
PS:中間出了點問題,令自己很是頭痛。由于數據庫的操作包括肯定會涉及到增刪改查,所以自己的方法得更改一下了,但是直接使用“立馬送藥”項目的數據庫操作方法時,卻出現了數據表只能讀,不能寫的狀況。自己需要一步步的排查問題,看看使用lmapp的數據表是否可以使用。
經過閱讀“立馬送藥”中數據庫操作的有關代碼,自己還是發現了一些端倪。MyDatabase.commit();這句意味深長。在操作之后添加這句后,居然就可以往數據庫中寫數據了。
通過實際操作,實現了數據庫的連接及新增Demo操作。接下來就需要將提取到的真實數據寫進數據庫存儲。
關于數據表lab_dynamic_order中ti與tout的存儲內容問題探討
首先注意到各交易的輸入、輸出參數的鍵是不同的,所以不可能在數據表中以字段形式展現,而是應該整體存儲在數據表內。結合以下用戶日志信息分析。
可得相應信息如下表所示,時間因素已在數據表中記錄,故輸入參數ti中不再體現。
tid
ti
tout
9015
{“stat”:“1”}
{“cnt”:0}
9101
{null}
{"data":[{"advid":"2","url":"AngularJSunny.jpg"},...,{"advid":"5","url":"VIP.jpg"}]}
9104
{“version”:“1.2”}
{"errtext":"當前已是最新版本"}
receiver:{"old_billid":"","addrid":"6","shopid":"S18853883587","msg":"","yhhdid":"YH00000019","yhhdamt":2,"yhqid":"","yhqcnt":0,"yhqamt":0,"cnt":1,"meddata":[{"medid":"TH20013063","medcnt":1,"cfid":""}],"version":"1.0","fore_time":"2016-03-18 15:53:06","uid":"18353102068","tx_code":"3002"}
剛才在手機端模擬了用戶操作,明天記得將2016-05-16的日志提取出來。
通過再一次分析日志,發現自己的篩選方法存在問題。應該以“receiver:”開頭的字符串作為輸入參數的提取點。
以用戶軌跡為線索,用戶軌跡行為如下:
登錄(1002)-->搜索藥品(9002)-->選擇地址(1004)-->提交訂單(3002)
tid
ti
tout
1002
{“phone”:“18353102068”}
{“result”:登陸結果}
9002
{“classid”:分類編號}
{“pcnt”:返回數量}
9005
{“shopid”:藥店編號}
{“pcnt”:返回數量}
9101
{null}
{“data”:廣告詳情}
9103
{“advid”:廣告編號}
{“url”:廣告鏈接}
1004
{null}
{"addrs":[{"receiver":"孫華強","tel":"18853883586","addr":"北京市北京市朝陽區112號","addrid":1}]}
3002
{"old_billid":"","addrid":"1","shopid":"S18853883587","msg":"","yhhdid":"YH00000019","yhhdamt":2,"yhqid":"","yhqcnt":0,"yhqamt":0,"cnt":4,"meddata":[{"medid":"TH20013063","medcnt":1,"cfid":""},{"medid":"TZ44021940","medcnt":1,"cfid":""},{"medid":"TH10940251","medcnt":1,"cfid":""},{"medid":"TB20020918","medcnt":1,"cfid":""}]
{"billid":"LM201605163586476"}
注意其中的輸入輸出參數是經過篩選之后提取出來的。為此需要寫一個工具類,用來提取特定的輸入輸出參數。
測試情景1:
輸入:整理后的單用戶日志
18353102068:1002-->9002-->9002-->9002-->9005-->1004-->3002
輸出:靜態統計表、動態統計表
編輯
測試情景2:
輸入:整理后的多用戶日志
18353102068:1002-->9002-->9002-->9002-->9005-->1004-->3002
18353102066:1002-->9002-->9005-->1004-->3002
輸出:靜態統計表、動態統計表
編輯
測試情景3:
輸入:整理后的包含匿名用戶日志
18353102068:1002-->9002-->9002-->9002-->9005-->1004-->3002
18353102066:1002-->9002-->9005-->1004-->3002
$tempuser:9002-->9005-->9101-->9103
輸出:靜態統計表、動態統計表
測試情景4:
輸入:整理后的交叉請求案例日志
輸出:靜態統計表、動態統計表
測試情景5:
輸入:整理后的單用戶多階段日志
注:測試需在case長度至少為2的情況下進行。
18353102068:1002-->9002-->9002
18353102068:1002
輸出:靜態統計表、動態統計表
測試情景6:
輸入:整理后的多用戶多階段日志
注:測試需在case長度至少為2的情況下進行。
18353102068:1002(2016-05-16 11:27:45)-->9002-->9002(2016-05-16 11:27:47)
18353102066:1002(2016-05-16 12:27:45)-->1004-->3002(2016-05-16 12:37:54)
18353102068:1002(2016-05-17 11:27:45)
-->9002-->9002-->9002-->9005-->1004-->3002(2016-05-17 11:27:54)
18353102066:1002(2016-05-17 11:27:45)
-->9002->9005-->1004-->3002(2016-05-17 11:27:54)
輸出:靜態統計表、動態統計表
編輯
測試情景7:
輸入:整理后的包含匿名用戶多階段日志
注:測試需在case長度至少為2的情況下進行。
1.18353102068:1002(2016-05-16 11:27:45)-->9002-->9002(2016-05-16 11:27:47)
2.18353102066:1002(2016-05-16 12:27:45)-->1004-->3002(2016-05-16 12:37:54)
3.18353102068:1002(2016-05-17 11:27:45)
-->9002-->9002-->9002-->9005-->1004-->3002(2016-05-17 11:27:54)
4.18353102066:1002(2016-05-17 11:27:45)
-->9002->9005-->1004-->3002(2016-05-17 11:27:54)
5.$tempuser:9002(2016-05-17 11:35:54)-->9005-->9101-->9103(2016-05-17 11:39:54)
6.18353102066:1002(2016-05-17 12:27:45)-->1004-->3002(2016-05-17 12:37:54)
7.$tempuser:9002(2016-05-17 12:35:54)-->9101-->9103(2016-05-17 12:39:54)
輸出:靜態統計表、動態統計表
測試情景8:
輸入:實際用戶日志
問題
查看日志內容:
receiver:{"version":"1.0","fore_time":"2016-05-16 20:21:04","uid":"$tempuser","tx_code":"1001"}
receiver:{"version":"1.0","fore_time":"2016-05-16 20:21:22","uid":"$tempuser","tx_code":"1002"}
實際日志中居然出現了上面的請求信息。1001為注冊交易應該對應參數“phone”和“passwd”,但請求中并未包含,這是什么原因?
交易1001(注冊)、1002(登錄)均涉及到加密傳輸,在邏輯上可以解釋以上現象。移動端1001(注冊交易)代碼如下:
var data = {}; appCallServer($http, "1001", data, function(data) { $ionicLoading.hide(); var key = data.publickey; // 在此調用測試加密 var passwd = password; // 用戶密碼提交至此 data = { "phone": phonenum, // 用戶名提交至此 "passwd": MyRsaEncrypt(key, passwd) }; appCallServer($http, "1001", data, function(data) { if (data.result == "0000") { $ionicLoading.show({ template: "注冊成功" }); $timeout(function() { $ionicLoading.hide(); $scope.gotoLogin(phonenum, password); }, 1000); } }); }, function(data) { $ionicLoading.show({ template: data.errtext }); $timeout(function() { $ionicLoading.hide(); }, 1000); });
客戶端實現的業務邏輯是首先調用一次1001(此次請求參數為空),獲取到服務端返回的公鑰后,利用此公鑰對用戶所輸入的密碼進行加密操作。再次調用1001(此次請求參數為phone,passwd),完成用戶的注冊。1002邏輯同此。至此,以上問題得到了解釋。
為此,通過更改服務端邏輯:在1001,1002調用之前使用0000獲取公鑰,這樣就符合了自己的篩選規則:去除0000。
if(b.contains("result") && !"0000".equals(tx_code)){....}
整理后的日志中不會再出現1001、1002均不會存在不存在“phone”參數的現象。
注:在進行實際日志測試的時候遇到了瓶頸,交易紊亂,輸入輸出紊亂問題尤為突出。難道是生成日志方式有問題?
$tempuser:1001(2016-05-16 20:21:04)-->9101-->9103(2016-05-17 12:39:54)
18353102068:9104(2016-05-16 11:27:10)-->9101-->9002(2016-05-16 11:27:47)
編輯
輸出:靜態統計表、動態統計表
未完待續.....
參考文獻
1.Java進階(九)正則表達式_No Silver Bullet的博客-CSDN博客_java正則表達式1到9
2.在線JSON校驗格式化工具(Be JSON)
JSON 數據庫
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。