IM 消息空白的多种原因

2021-08-25  本文已影响0人  某非著名程序员

串行队列阻塞引起消息加载慢:之前这篇文章讲过,在弱网快速进入会话、退出再进入会话会导致消息空白。原因是再拉取历史消息时,信号量阻塞了当前请求网络的串行队列,导致消息加载慢而空白。

原因二:弱网情况下反复进出会话,导致错误删除本地融合块。(偶现)

考虑到弱网环境,我们针对消息做了一套单独的缓存策略,来保证消息已经拉取过不会再去服务端拉取;同时又要保证消息的连续性。
如何提升弱网的体验

在弱网情况下,快速进入会话,再退出,再进入。
假设本地有块[501-600],从500开始加载历史数据[481-500]。弱网情况下快速进出会话[481-500]与[501-600]合并,第一次合并块时[481-600],[481-500]与[481-600]再合并一次。

导致本地的消息融合块被删掉。

if(minId>=up_block_start && minId<=up_block_end){//卡在中间,可以融合
    if (lastBlockStart != -1) {
        i[self.chatMsgBlockService deleteBlock:conferenceId blockId:up_block_start];
        [self.chatMsgBlockService updateBlockStart:conferenceId blockId:lastBlockStart newBlockId:up_block_start];
    }else{
        [self.chatMsgBlockService updateBlockEnd:conferenceId blockId:up_block_start blockEndId:endId];
    }
}

代码中是先删up_block_start = 481,[481-600]这个块,再update。DB的最大块已经被删掉了。导致弱网时DB没有拉取到数据,去网络拉取消息也没有回来,消息屏幕展示为空白效果。

由于融合算法本身复杂,出现问题的概率比较低。问题难以排查。经过长时间的检验,算法还是比较稳定。

原因三:多线程问题,导致取到的消息为空。

- (NSArray *)reloadConversationMessagesTimeline:(BLConversation *)conversation {
   ...
    conversation.messageSource.messages = [tempMessages mutableCopy];
   ...
}

- (void)messageDataSourceCopy{
    self.messageDataSource = [self.conversation.messageSource.messages mutableCopy];
    if (self.messageDataSource.count == 0) {
        BLLogInfo(@"消息为空");
    }
}

下面是思考后对原生代码的还原的一段测试代码:

@interface ViewController ()
@property (nonatomic,strong) NSMutableArray * datas;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"%@-%@",NSStringFromClass(objc_getClass("ViewController")),NSStringFromSelector(_cmd));
    
    _datas = [NSMutableArray new];
    
    dispatch_queue_t concurrentQueue = dispatch_queue_create("QUEUE_CONCURRENT", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^{
        NSMutableArray * arr = [NSMutableArray new];
        for (int i = 0; i<10000; i++) {
            [arr addObject:@(i)];
            self.datas = arr.mutableCopy;
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (int i = 100; i<20000; i++) {
            NSLog(@"结果:%d",self.datas.count);
        }
    });
}

@end


2021-08-18 23:11:24.330597+0800 Test[17723:1301363] 结果:0
2021-08-18 23:11:24.352679+0800 Test[17723:1301363] 结果:0

结果偶现为空,也有时崩溃。

总结

  1. 消息是一个相对复杂的模块,融合算法的应用、多线程环境下的考验,弱网场景下的消息处理。都带来巨大的挑战。
  2. 尽力解决每个偶现问题,软件才能更加稳定。第二个问题加了各种日志,分析很久才确定了原因;第三个多线程问题,分析完后是简单,但掺杂在消息复杂的代码中,找出问题也比较困难。特别在综合多种原因下,更加困难。
上一篇下一篇

猜你喜欢

热点阅读