記一次redis併發處理問題

記一次redis併發處理問題

1、場景分析

所在的公司是物聯網公司,涉及到向設備發送指令,如今的問題是在和天貓語音對接的一個產品線上出現了一個bugphp

啓用組合指令模式,例如一個情景模式,一、開臥室燈、2開走廊燈、3開客廳燈
  • 上面的三個燈對於咱們的產品來講就是一個開關面板,面板上面是一個三路開關,也就是每個燈對應一個開關,以下圖:

image

當天貓精靈一條控制指令發送過來,我在將指令發送給設備,流程圖以下

image

2、流程分析

上面能夠看到整個流程,包括天貓語音觸發應用雲到下發控制指令的過程,
那幾乎能夠把重點鎖定在下發參數上面redis

1.下發二進制指令

  • 如今有三路面板 對應的是 1 1 1 二進制位,公司最可能是8路開關
  • 則如上面的流程所示,當控制客廳的時候 下發參數 0 0 0 0 0 1 0 0

2.緩存機制

上面也看到了,在下發控制指令的時候會將 其餘開關位的狀態也帶上。緩存

  • 那麼實際在控制的時候,會去查下其餘開關位的狀態
  • 那麼這個緩存狀態是由設備來更新的
到這裏來看,幾乎也不會出現啥問題,接下來咱們就要直面真正遇到的問題

3、併發問題分析

上面的例子都是單次請求,由於同一個面板的不一樣開關位雖然會依賴設備更新緩存,可是單次控制佔時仍是沒有問題的,也就是用戶觸發天貓控制燈的時候都是一個一個控制的併發

可是如今引入了場景,也就是天貓精靈上面有場景模式,例如設置場景 回家了,那麼就是三路開關上全部的燈都要打開全部的燈,!並且天貓精靈是併發處理的,也就是會把三個請求同時發送到應用雲上,而後應用雲在下發控制指令。

問題分析

那麼問題來了,三次請求之間都是有依賴關係的
  • 列如開客廳燈會查詢走廊燈的狀態,還有臥室燈的狀態,都會去查詢緩存,而三條控制指令都是同時到達,那麼設備尚未更新緩存
  • 好比臥室燈(00000100) 走廊燈(00000101)已經開了,可是客廳燈最後進來,發現其餘燈的緩存都是關的,那麼會將0帶下去((00000010)),而後致使前兩次的燈開了又關。

4、優化處理方案

1.不依賴設備更新緩存,採用臨時緩存

也就是不用去查詢設備的緩存,直接採用臨時緩存 ,時間1-2s,當併發的三個請求同時到來時,直接存儲一個臨時值,告訴其餘請求針對要控制的面板有其餘開關在控制
服務端採用的sowole進程模型
//採用hash結構,每個案件對應一個key值,
//每個按鍵的請求到來時更新hashkey時間爲1s
$redis->hset("concurrent_control_hash_off".$devSn,$keynum,1);
$redis->expire("concurrent_control_hash_off".$devSn,1);
//直接從臨時緩存裏獲取,若是沒有在去設備緩存裏獲取
$res = $redis->hGetAll("concurrent_control_hash_off".$devSn);
  • 上訴的方法的方法在高併發下仍是有問題!

2.保證單次請求的redis操做原子性

也就是當併發請求的時候每條redis指令沒有順序
$redis->multi();
$redis->hset("concurrent_control_hash_on".$devSn,$keynum,1);
$redis->expire("concurrent_control_hash_on".$devSn,1);
$redis->hGetAll("concurrent_control_hash_on".$devSn);
$res = $redis->exec();
$concurrentArr = $res[2];
  • @multi()
  • @exec()

保持原子操做,效果到如今爲止要好了些高併發

總結

即便上面根據流程作了屢次修改,已經對接流程的修改,總之沒有絕對的狀況,都須要進行優化,併發測試測試

相關文章
相關標籤/搜索