91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》
  • 首頁 > 
  • 教程 > 
  • 數據庫 > 
  • Redis SortedSet結構score字段丟失精度問題解決辦法是什么

Redis SortedSet結構score字段丟失精度問題解決辦法是什么

發布時間:2021-12-08 14:35:21 來源:億速云 閱讀:399 作者:柒染 欄目:數據庫

這期內容當中小編將會給大家帶來有關Redis SortedSet結構score字段丟失精度問題解決辦法是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

一、問題現象

項目中采用Redis SortedSet存儲用戶的離線消息,score值存儲的msgid(消息ID)。msgid采用snowflake算法生成,按照時間有序。

生成的msgid有18位十進制整數,例如 215857550229364736

我們發現數值很接近的msgid,在redis中無法通過score進行區分。

舉個列子,在redis中tzset結構里存入如下幾條數據  

ZADD tzset 215857497028812800 test1

ZADD tzset 215857540511162369 test2

ZADD tzset 215857550229364736 test3

ZADD tzset 215857550229364737 test4

查詢看一下結果 

Redis SortedSet結構score字段丟失精度問題解決辦法是什么

我們發現score值采用科學計數法表示,test3,test4兩個元素的score值顯示是一樣的。

使用score=215857550229364736 執行查詢,結果如下圖 

Redis SortedSet結構score字段丟失精度問題解決辦法是什么

使用215857550229364736查詢,結果score為215857550229364737的test4也被查出來了

用215857550229364739去查,竟然也能查出來 

Redis SortedSet結構score字段丟失精度問題解決辦法是什么

這一現象給我們的系統功能帶了困擾,會影響到消息同步TimeLine的精確性(參看《基于TimeLine模型的消息同步機制》)。

二、問題原因

查詢相關資料發現Sorted Sets中的Score是double類型,我們的msgid是long類型。問題是long轉換為double時,丟失精度。

1、snowflake算法簡介

消息ID采用snowflake算法,采用64位二進制整數。二進制具體位數含義如下圖。

Redis SortedSet結構score字段丟失精度問題解決辦法是什么

1位,不用。二進制中最高位為1的都是負數,但是我們生成的id都使用正數,所以這個最高位固定是0

41位,用來記錄時間戳(毫秒)。

如果只用來表示正整數(計算機中正數包含0),可以表示的數值范圍是:0 至 241?1,減1是因為可表示的數值范圍是從0開始算的,而不是1。

也就是說41位可以表示241?1個毫秒的值,轉化成單位年則是(241?1)/(1000?60?60?24?365)=69年

10位,用來記錄工作機器id。

可以部署在1024個節點,包括5位datacenterId和5位workerId

12位,序列號,用來記錄同毫秒內產生的不同id。

12位(bit)可以表示的最大正整數是4095,即可以用0、1、2、3、....4095這4096個數字,來表示同一機器同一時間截(毫秒)內產生的4096個ID序號

2、doublel數據結構

double數據的結構如下圖 

Redis SortedSet結構score字段丟失精度問題解決辦法是什么

3、問題定位

63bit(去掉符號位)的數轉換為52bit的數,從某一位開始進行了四舍五入,導致精度下降。所以215857550229364736、215857550229364737、215857550229364739三個數據被轉換為double類型后,計算機認為是相同的數。

三、解決辦法

問題找到了,怎么解決呢?

id生成策略要保證整個系統生命周期類所有ID唯一,設計一個52bit的ID生成器保證ID唯一難度較大。

Redis的score數據類型更是修改不了

用52bit來表示63bit的數據一定會丟失信息,長整型long默認轉換為double的方式丟失的信息會影響到業務,能不能結合業務特點自定義一種轉換(映射)方式,答案是肯定的。

有以下幾種想法

1、因為Redis緩存的消息最多保存15天(假設)或者最多保存多少條。能不能截去41位時間戳的部分高位,確保Redis緩存時間周期內時間戳長度夠用就行呢?計算了一下長度 log(15*24*60*60*1000)=30.2,大約30位二進制數即可在現有規則下表示15天時間。所以將41位時間戳的前11位屏蔽掉,可以節約11位二進制信息。這樣63bit剛好能用52bit來表示。

然而這個方式有個致命問題,當15天時間周期到了后,時間戳會變得特別小(新的周期),這導致上一個周期后邊的數據Score值大于新周期。消息順序混亂了,會導致拉離線丟消息,這不能接受!

2、去掉10bit工作機id和序列號的最高位bit。

去掉這11bit,不會對消息的順序造成影響,但是可能造成score數值沖突(相同)。分析一下score沖突的可能性。

(1)12bit序列號能表示4096個數。去掉最高位,能表示2048個數。所以單個msgid生成節點(dispatch模塊)每毫秒,每個用戶要超過2048條消息,才可能出現score重復。這個基本不可能發生。

(2)去掉10bit工作機id號,需要同一毫秒,同一用戶在不同的dispatch節點都接收到消息,score才可能沖突。即使出現這種情況,由于12位序列號我們做了模128的隨機分布(解決分庫問題),即使出現同一毫秒不同disptch生成同一用戶msgid的情況下,score沖突的概率還要除以 128*128。這個概率非常低。

(3)即使出現了score沖突(兩條消息有相同score),最多造成拉取離線消息多拉取相同score的消息(本來一次拉取10條離線,結果可能拉到11條),對業務也沒有影響。

因此采用去掉10bit工作機id和序列號的最高位bit將63bit(不含符號位)的msgid轉換成52bit的score對業務上沒有影響。同時解決了redis sorted set丟失精度的問題。 

因此采用去掉10bit工作機id和序列號的最高位bit將63bit(不含符號位)的msgid轉換成52bit的score對業務上沒有影響。同時解決了redis sorted set丟失精度的問題。

上述就是小編為大家分享的Redis SortedSet結構score字段丟失精度問題解決辦法是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

瑞昌市| 宜宾县| 通山县| 东丰县| 隆子县| 平山县| 晋州市| 克拉玛依市| 汉寿县| 延津县| 保康县| 定南县| 宁德市| 兴海县| 尼木县| 天峻县| 剑阁县| 潼南县| 榆中县| 廉江市| 开原市| 蒙城县| 宣威市| 沁水县| 营山县| 夏河县| 贵南县| 新巴尔虎左旗| 葫芦岛市| 万源市| 湟中县| 富锦市| 将乐县| 株洲市| 巩义市| 合江县| 临颍县| 诸暨市| 宁化县| 门源| 手游|