iOS 點贊功能高併發的思考

前言

image.png
微博上熱點的點贊數數W。服務器遇到這麼高併發請求壓力確定很大。數據庫要怎麼寫入這些點贊就不探究了(真是個大工程,若是每接收一條就寫入一次),只探究iOS手機端怎麼處理點贊功能。

本文將參考微信和微博,猜想其實現,並探究如何處理點贊功能。數據庫

微信朋友圈的點贊數相對來講少。微博的點贊數能達五位數。其應該採用了不一樣的策略。bash


先從宏觀上思考這個問題。

分爲兩類 何時獲取服務器最新點贊數 點贊按鈕與網絡的交互服務器

  • 手機端不會對每一條消息實時跟蹤點贊數,在某些情景下才會請求數據(進入詳情頁等)。
  • 若是每次點擊 點贊/取消點贊 按鈕,就發送一次請求,用戶指望是最後一次操做的效果。可是若遇到網絡問題,最終寫入數據庫的值就沒法控制了。那麼按鈕事件應該如何處理呢?

何時獲取服務器最新點贊

  • 先研究微博 微信

    微博獲取點贊數
    對於別人的微博。 能夠看到一開始是採用本地存儲的贊數,點進去詳情頁後纔會向網絡獲取一次點贊數,而且更新本地存儲的。(僅發起一次)

    針對本身發的微博就不研究了,萬年不發一條微博,印象中是收到點贊會收到推送的。網絡

  • 再研究微信併發

    1. 打開朋友圈,先用本地的數據,可是當滑動到某一條別人發的朋友圈時。若是有新的贊,會顯示出來(有延遲,應該是網絡請求滯後)。socket

    2. 再來看本身發的朋友圈,收到點贊紅點後,滑動下去發現這個贊就躺在那了,無延遲。若是視圖鎖定在本身發的朋友圈內(以下圖),點贊也會更新,由於有收到紅點動態。即收到紅點動態的時候,也會得到點贊信息,有必要的話刷新UI。 別人對本身發的朋友圈首次點贊👇 高併發

      首次點贊

    3. 對第二點再深刻點。本身發的朋友圈,若是某我的點了贊,查看完紅點後,這我的取消->再次點贊。微信不會顯示紅點。換言之,不屬於新動態。spa

    4. 點了別人的贊後,該條朋友圈有新動態也會刷新點贊信息。code

    5. 點進詳情頁一定會刷新。

    因此大膽猜想,對本身跟蹤的朋友圈,會有個特殊的API獲知哪一條朋友圈的新動態。該API可能採用定時訪問,偶爾就訪問一次;聽杜優秀說多是socket或者protobuf這種高速的http請求。

  • 總結

    1. 滑到cell處對該cell進行刷新(一次)。
    2. 採用一個特殊的API,獲取跟蹤的新信息。
    3. 進詳情頁一定獲取一次最新點贊信息。

固然具體的情形遠比這複雜,以上也就是我的瞎猜的。

點贊按鈕與網絡的交互

因爲網絡的不穩定性 以及 用戶可能隨時關閉App致使未成功發出請求,用戶指望的點贊狀態與數據庫的數據不管如何也不能保證必定一致。

可是如何儘量地實現一致呢?針對這個問題提出我的的愚見。

仍是先從微信和微博入手思考。

  • 無網狀態下

    微博UI不變狀態,固然也不發出請求。

    微信UI有點贊效果

    一開始是沒有點讚的,最終UI設爲點贊。

    順便說說結果,連上網後詳情頁發現確實設了點贊。

    可是若是關閉微信,再打開,會發現點贊不見了。

  • 不好的網絡狀態下

    2G網絡實測,三條微博從無點贊狀態 按了好幾回點贊又取消,退出App連4G後打開看服務器的狀態,發現有些點了贊,有些沒有。即難以肯定。

    2G網絡實測,微信點贊後取消點贊,UI忽然變成點贊狀態了。應該是請求成功後刷新本地數據和UI。

  • 如何實現比較合理

如下純屬我的愚見,若是有更好的實現方法,歡迎大佬提出來。

首先是 UI如何顯示

先說個簡單萬能的方法。

有時候,用戶有意識發起的網絡請求,咱們都會顯示「加載中」甚至不讓用戶點擊。而後在請求成功處理數據完成後,再讓用戶點擊。例如登陸界面,點擊登陸後,咱們會顯示"登陸中",而且禁止用戶進行其餘操做。類比着,點贊後,不讓用戶進行其餘操做,顯示「發起請求中」。成功就更換按鈕狀態,失敗提示"點贊失敗/取消點贊失敗"。這樣雖然能徹底避免高併發以及指望值不同但用戶不知道的狀況。

然而,這種方法用戶體驗並很差。可是若是選擇了用戶體驗,帶來的問題是用戶或許無聊會一直點按鈕,高併發請求,對手機內存和服務器都形成了巨大壓力。也有可能最後寫入服務器的數據並非用戶指望值。但主流App都會爲了用戶體驗,承擔這些後果。

因此除了在服務器那加進處理外,手機端也有必要減小高併發的壓力。

在這我更傾向於微信的作法,讓按鈕二級view顯示,這就減小了用戶誤點贊後取消點讚的可能。並且也給了時間完成網絡請求。

還有一種想法是,先讓UI更改,請求失敗就改回去,而且提示「請求失敗」。 微信裏會小紅點提示「點贊未發送」。應該是相似的。

而後是 何時要發起網絡請求

微博那個我並無看懂,有網狀況下,每次點擊都會發起請求,而後隨緣看最後一次的結果嗎?

微信的點贊請求應該是立刻發出的,但取消點贊很難說。由於2G時,點贊後立刻取消點贊,最終結果倒是點贊。

每次點擊都發送是最容易形成高併發指望值誤差 的操做。 因此不建議每次點擊都發送這種隨緣法。

  • 方法一

猜想微信裏應該是更改第一次請求,請求期間點擊按鈕都只是更改個樣子看看,而且請求成功後刷新本地數據和UI。而後才容許下一次請求。

那麼就會有一個問題,微博上剛剛發送點贊請求,而後又點進了詳情頁。因此在點跳轉以前判斷,沒有請求完成就在詳情控制器中註冊了一個通知。當請求成功後,發送通知,通知詳情控制器刷新數據。

猜想代碼以下

NSMutableArray *isRequestingArray;//保存每個cell 是否在發起網絡請求的BOOL

- (void)btnClick:(UIButton *)btn atIndexPath:(NSIndexPath *)indexPath {
    // 更改btn的樣子
    btn.selected = !btn.selected; 
    // 還要修改本地的數據 點擊進詳情頁要看到狀態變了
    // 最後根據判斷髮起網絡請求
    if (![_isRequestingArray[indexPath.section][indexPath.row] boolValue]) { // 無其餘請求
        //設置正在請求
        _isRequestingArray[indexPath.section][indexPath.row] = @"1"; 
        __weak typeof(self) wself = self;
        [PraiseAPI startWithSuccessBlock:^(__kindof BaseRequest *request){
            __strong typeof(wself) sself = wself;
            sself->isRequestingArray[indexPath.section][indexPath.row] = @"0";
            // 更改btn的樣子
            // 修改本地的數據
            // 發送通知
        } failureBlock:^(__kindof BaseRequest *request, NSError *error) {
            __strong typeof(wself) sself = wself;
            sself->isRequestingArray[indexPath.section][indexPath.row] = @"0";
            // 恢復btn的樣子
        }];
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NextViewcontroller *nextVC = [[NextViewcontroller alloc] init];
    if ([_isRequestingArray[indexPath.section][indexPath.row] boolValue]) {
        //正在請求  nextVC添加通知
    }
    [self.navigationController pushViewController:nextVC animated:YES];
}
複製代碼
  • 方法二 可是微博那些可能會手誤點了贊,因而立刻就取消點贊。這時候採用第一種方法就不太好了。這時候咱們就要採用延遲發送請求的策略。

若點擊後2s內無再次點擊,而且和原狀態不同,才發起網絡請求。在視圖退出界面的時候也立刻發起網絡請求。

  • 方法三 聽某位朋友說,接口裏加個當前時間進去。服務器按最後一次時間來寫入。問題是並無解決高併發問題。

想得還不是很完善,但願能拋磚引玉。

相關文章
相關標籤/搜索