美文网首页好东西小知识点iOS学习专题
iOS 点赞功能高并发的思考

iOS 点赞功能高并发的思考

作者: Hsusue | 来源:发表于2018-08-02 22:05 被阅读25次

    前言

    image.png

    微博上热点的点赞数数W。服务器遇到这么高并发请求压力肯定很大。数据库要怎么写入这些点赞就不探究了(真是个大工程,如果每接受一条就写入一次),只探究iOS手机端怎么处理点赞功能。

    本文将参考微信和微博,猜测其实现,并探究如何处理点赞功能。

    微信朋友圈的点赞数相对来说少。微博的点赞数能达五位数。其应该采用了不同的策略。


    先从宏观上思考这个问题。

    分为两类 什么时候获取服务器最新点赞数 点赞按钮与网络的交互

    • 手机端不会对每一条消息实时跟踪点赞数,在某些情景下才会请求数据(进入详情页等)。
    • 如果每次点击 点赞/取消点赞 按钮,就发送一次请求,用户期望是最后一次操作的效果。但是若遇到网络问题,最终写入数据库的值就无法控制了。那么按钮事件应该如何处理呢?

    什么时候获取服务器最新点赞

    • 先研究微博


      微博获取点赞数

      对于别人的微博。
      可以看到一开始是采用本地存储的赞数,点进去详情页后才会向网络获取一次点赞数,并且更新本地存储的。(仅发起一次)

      针对自己发的微博就不研究了,万年不发一条微博,印象中是收到点赞会收到推送的。

    • 再研究微信

      1. 打开朋友圈,先用本地的数据,但是当滑动到某一条别人发的朋友圈时。如果有新的赞,会显示出来(有延迟,应该是网络请求滞后)。

      2. 再来看自己发的朋友圈,收到点赞红点后,滑动下去发现这个赞就躺在那了,无延迟。如果视图锁定在自己发的朋友圈内(如下图),点赞也会更新,因为有收到红点动态。即收到红点动态的时候,也会获得点赞信息,有必要的话刷新UI。
        别人对自己发的朋友圈首次点赞👇


        首次点赞
      3. 对第二点再深入点。自己发的朋友圈,如果某个人点了赞,查看完红点后,这个人取消->再次点赞。微信不会显示红点。换言之,不属于新动态。

      4. 点了别人的赞后,该条朋友圈有新动态也会刷新点赞信息。

      5. 点进详情页必定会刷新。

      所以大胆猜测,对自己跟踪的朋友圈,会有个特殊的API获知哪一条朋友圈的新动态。该API可能采用定时访问,偶尔就访问一次;听杜优秀说可能是socket或者protobuf这种高速的http请求。

    • 总结

      1. 滑到cell处对该cell进行刷新(一次)。
      2. 采用一个特殊的API,获取跟踪的新信息。
      3. 进详情页必定获取一次最新点赞信息。

    当然具体的情形远比这复杂,以上也就是个人瞎猜的。

    点赞按钮与网络的交互

    由于网络的不稳定性 以及 用户可能随时关闭App导致未成功发出请求,用户期望的点赞状态与数据库的数据无论如何也不能保证一定一致。

    但是如何尽可能地实现一致呢?针对这个问题提出个人的愚见。

    还是先从微信和微博入手思考。

    • 无网状态下

      微博UI不变状态,当然也不发出请求。


      image

      微信UI有点赞效果

      一开始是没有点赞的,最终UI设为点赞。

      顺便说说结果,连上网后详情页发现确实设了点赞。

      但是如果关闭微信,再打开,会发现点赞不见了。

    image
    • 很差的网络状态下

      2G网络实测,三条微博从无点赞状态 按了好几次点赞又取消,退出App连4G后打开看服务器的状态,发现有些点了赞,有些没有。即难以确定。

      2G网络实测,微信点赞后取消点赞,UI突然变成点赞状态了。应该是请求成功后刷新本地数据和UI。

    image
    • 如何实现比较合理

    以下纯属个人愚见,如果有更好的实现方法,欢迎大佬提出来。

    首先是 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]) { // 无其他请求
            //设置正在请求
            _isRequestingArray[indexPath.section][indexPath.row] = YES; 
            __weak typeof(self) wself = self;
            [PraiseAPI startWithSuccessBlock:^(__kindof BaseRequest *request){
                __strong typeof(wself) sself = wself;
                sself->isRequestingArray[indexPath.section][indexPath.row] = NO;
                // 更改btn的样子
                // 修改本地的数据
                // 发送通知
            } failureBlock:^(__kindof BaseRequest *request, NSError *error) {
                __strong typeof(wself) sself = wself;
                sself->isRequestingArray[indexPath.section][indexPath.row] = NO;
                // 恢复btn的样子
            }];
        }
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        NextViewcontroller *nextVC = [[NextViewcontroller alloc] init];
        if (_isRequestingArray[indexPath.section][indexPath.row]) {
            //正在请求  nextVC添加通知
        }
        [self.navigationController pushViewController:nextVC animated:YES];
    }
    
    • 方法二
      但是微博那些可能会手误点了赞,于是马上就取消点赞。这时候采用第一种方法就不太好了。这时候我们就要采用延迟发送请求的策略。

    若点击后2s内无再次点击,并且和原状态不一样,才发起网络请求。在视图退出界面的时候也马上发起网络请求。

    • 方法三
      听某位朋友说,接口里加个当前时间进去。服务器按最后一次时间来写入。问题是并没有解决高并发问题。

    想得还不是很完善,希望能抛砖引玉。

    相关文章

      网友评论

        本文标题:iOS 点赞功能高并发的思考

        本文链接:https://www.haomeiwen.com/subject/fqhevftx.html