一、回顧
之前的登陸流程在這篇里。之前的登陸流程簡述:
(1)先檢查是否同服已登陸,是則兩個鏈接都踢掉,否則進(jìn)入下步;
(2)判斷是否異服已登陸,是則告訴異服踢老鏈接,隨后踢自己這的新鏈接。否則進(jìn)入下步;
(3)當(dāng)前服務(wù)器登陸相關(guān)流程走完后,向玩家在線列表匯報(寫入這個玩家登陸的服務(wù)器id為我)。這時的匯報寫入為redis的CAS操作,為了檢查是否發(fā)生了那篇里介紹的同賬號瞬間多起登陸事件。CAS操作成功,本服鏈接登陸完成,做后續(xù)操作。否則CAS操作失敗,表示瞬時登陸的異服同賬號的另一個鏈接的登陸流程走的快,已經(jīng)完成整個流程,包括匯報進(jìn)在線列表。這時的處理只用將慢拍的本服鏈接關(guān)閉就行了。
二、存儲架構(gòu)變?yōu)閞edis+mysql后的問題
現(xiàn)在玩家上線時需要從mysql加載玩家離線數(shù)據(jù)到redis,需要考慮這個數(shù)據(jù)加載放到上邊登陸流程哪一步里。
首先數(shù)據(jù)加載有可能會失敗,如果數(shù)據(jù)加載出問題,就不能讓該玩家登陸。
如果放到(2)(3)之間,就是redis的CAS之前,這樣瞬間同一賬號多起登陸都有可能開始進(jìn)行加載數(shù)據(jù)步驟,而處理的快的那個客戶端就有可能匯報登陸完成之后立即玩游戲并更新了自己在redis里的數(shù)據(jù),處理的慢的客戶端還這時還在將mysql的數(shù)據(jù)往redis的加載,會覆蓋快的客戶端更新的數(shù)據(jù)。
如果放到(3)里redis的CAS之后,數(shù)據(jù)加載失敗,就需要回退CAS的操作。
可見第二種至少可以保證數(shù)據(jù)正確性。這種情況抽象下,就是第一種里沒有提供事務(wù)操作的回滾(慢客戶端覆蓋數(shù)據(jù)后發(fā)現(xiàn)干了壞事卻不方便回滾自己的破壞)。
(2)這個操作當(dāng)時是為了區(qū)分異服登陸并玩游戲很久了和瞬間多起登陸這兩種情況的。現(xiàn)在想想這兩種情況的處理統(tǒng)一為直接踢掉新舊兩個鏈接也沒什么,畢竟瞬時登陸的情況不多。
三、新流程
根據(jù)上邊的結(jié)論,新的流程為:
(1)先檢查是否同服已登陸,是則兩個鏈接都踢掉,否則進(jìn)入下步;
(2)向玩家在線列表CAS報告自己登陸。如果失敗告訴異服踢掉該賬號老鏈接,自己這邊踢掉該賬號新鏈接即可。成功則進(jìn)入下步;
(3)加載數(shù)據(jù),成功就進(jìn)入正常游戲流程。加載失敗,就去在線列表里清掉自己。