视频缓存加速,2.5倍优化

该文章属于刘小壮原创,转载请注明:刘小壮


背景

视频缓存已经成为各大视频App的标配,并且从功能使用数据来看,每个月使用的量都很大。所以,做好缓存功能的优化,对提升用户体验有非常重要的作用。

搜狐视频iOS端的缓存和爱奇艺的有区别,并没有多个视频同时缓存的产品功能,而且缓存分片是串行下载的。即m3u8文件缓存下来后,顺序下载ts地址对应的文件,导致网络利用率不高。

为了提升用户体验,提升缓存速度,我对缓存进行了速度优化,提升了网络利用率。具体方案如下。

方案设计

分析

缓存方案的核心在于,最大程度的提升网络利用率。但并非单纯的扩大并发缓存数量,这样会导致设备发烫、网络资源抢夺等很多问题。应该根据网速和设备性能等因素,动态决定分片数量。所以,设计一套合理的测速方案,以及缓存方案就非常重要。

由于我们的网络使用的quic协议,所以在网络层面已经没有太大的提升空间,只能通过上层进行优化。

缓存方案

如果是新建的缓存任务,没有测速数据或数据已过时。数据已过时指的是两次缓存不是连续的,例如暂停后再继续缓存,或重启后缓存。则根据网络环境做判断,来决定并行下载数量。流量环境并行数量为2,WiFi并行数量为4。这个值是测试的一个经验值。

并发数量并不是固定的,从第一次下载开始,每次缓存的过程都会进行测速,并根据测速结果动态修改并发数量,并且持续利用缓存的速度数据进行测速,来修改并发数量。当网络环境发生改变后,这时候需要重新进行测速,从第一步重新开始。

在网络的部分,底层quic使用的cronet库作为实现。cronet没有长连接的概念,是通过cronet线程处理的并发,同一端口最多6条线程,最多不超过16条线程。所以,需要上层逻辑控制并发数,并不能直接设置并发数。

由于项目中大多数的视频都是m3u8格式,缓存加速只对m3u8的视频缓存做了加速,drmmp4格式的视频并没做处理。而且,drmmp4目前是流式下载,如果想加速需要后端对视频文件做切片。

测速方案

测速需要考虑下面几个核心因素。

  1. 网络环境,WiFi和流量的平均网速相差比较大,WiFi下可以更充分的利用网络资源。
  2. 网速,最核心的因素,网速慢的话,什么方案都没用。
  3. 设备性能,同样的网速,在不同设备上表现可能不一样。低版本设备并发数太多,可能会导致卡顿或发热严重。
  4. 视频类型,电影单个剧集ts数量较多,缓存时间长且连贯,所以可以适当增加并发数。

并发数需要控制在一个合理的区间,如果下载并发数太多,会造成请求拥堵,从而触发timeout。如果下载并发数过少,会导致网络利用率不高。

并且,不只要考虑缓存部分,还需要考虑是否会抢夺其他请求的资源。否则会导致其他非缓存的请求,由于缓存占用带宽过多,导致请求变慢或大量触发timeout

测速方案经过实践验证,根据上述因素设置不同的权值。在考虑因素的过程中,还需要防止手机发烫的问题,所以需要多次测试才能决定权值。方案的核心在于,最大限度的利用用户的带宽,以及设备性能,并且和发热保持一个良好的平衡。温度适中,并且不会影响fps

下图是整个缓存方案的一个流程图,看图比较直观。

测试数据

测试方法

由于还未上线,所以数据来源于控制台日志,但经过多次以及不同网络环境下的测试。缓存类型为电影和电视剧,表格中前两列为电影,后两列为电视剧。

测试方法,在同一时间缓存同一剧集,相同清晰度,对比线上版本和缓存加速版本的差别,分别测试WiFi和流量环境。在测试阶段,设备始终在前台。

从数据来看,电影由于文件比较大,在网速快的情况下提升比较明显。电视剧由于网速刚上来就下载完了,数据没有这么明显,但也有50%左右的提升。

同时对下半年缓存数据进行了下统计分析,流量环境下的缓存的只占二十分之一左右,可以看出WiFi环境下是占绝大多数的。所以,WiFi环境下加速,可以更好的让用户享受到缓存加速带来的优化体验。

鉴于使用缓存功能的用户,大多数都是在WiFi环境下使用,所以主要还是以WiFi的数据为准。WiFi环境分别测试了公司WiFi,和我家里的WiFi,可以代表很多WiFi网络环境了。下面是不同网络环境下,多次测试的平均结果。

WiFi

经过多次测试,平均提速为2.35倍。

流量

经过多次测试,平均提速为1.50倍。

播放流畅性

为了防止缓存抢夺过多网络资源,从而影响播放的流畅性,对WiFi和流量环境下,缓存电视剧和电影进行了测试。测试结果表明,不同网络环境下缓存电视剧和电影,不会对播放流畅性造成影响,播放视频始终在60fps

代码实现

下面是实现的核心逻辑的伪代码,主要为了体现测速的代码流程。

/// 计算当前并发数量,所有缓存任务用一个值,当网络发生变化或者重新开始时,使用默认值
/// 下面计算核心准则在于,最大程度利用真实带宽
- (void)calculateDownloadSpeedWithTask:(SVDownloadTask *)downloadTask {
    /// 根据网速设置并发下载数量,网速单位判断为:mb/s
    CGFloat currentSpeed = downloadTask.downloadingSpeed / 1024.f / 1024.f;
    NSInteger maxConcurrentCount = 4.f;
    
    /// 以电视剧为例,一个ts大小在1MB~2MB之间,也有少部分在这个区间之外,比例20%左右
    /// ts文件一半以上都在1MB~1.5MB之间,并发数和网速并不是直接关系的,核心在于提高网络利用率,真正能用到多少网速
    if (currentSpeed > 0.f) {
        /// 网速在1MB以下的情况在流量环境下是很常见的
        /// 阈值的区间设定应当遵从泊松分布,越小的部分越细
        if (currentSpeed < 0.5f) {
            maxConcurrentCount = 2;
        }
        else if (currentSpeed >= 0.5f && currentSpeed <= 1.f) {
            maxConcurrentCount = 4;
        }
        else if (currentSpeed >= 1.f && currentSpeed <= 2.f) {
            maxConcurrentCount = 5;
        }
        else if (currentSpeed >= 2.f && currentSpeed <= 3.f) {
            maxConcurrentCount = 6;
        }
        else if (currentSpeed >= 3.f && currentSpeed <= 4.f) {
            maxConcurrentCount = 7;
        }
        else if (currentSpeed >= 4.f && currentSpeed <= 5.f) {
            maxConcurrentCount = 8;
        }
        else if (currentSpeed >= 5.f && currentSpeed <= 7.f) {
            maxConcurrentCount = 10;
        }
        else if (currentSpeed >= 7.f && currentSpeed <= 10.f) {
            maxConcurrentCount = 12;
        }
        else if (currentSpeed >= 10.f && currentSpeed <= 12.f) {
            maxConcurrentCount = 16;
        }
        else if (currentSpeed >= 12.f && currentSpeed <= 16.f) {
            maxConcurrentCount = 18;
        }
        else if (currentSpeed >= 16.f) {
            maxConcurrentCount = 20;
        }
        
        NSInteger dataType = downloadTask.dataType;
        /// 如果在视频刚下载的时候,网速计算可能会低于实际网速,所以在前期阶段可以适当增加并发数,后期不适用
        if (downloadTask.downloadSuccessCount < 6 && currentSpeed > 0.3f) {
            maxConcurrentCount += 2;
        }
        /// 如果是电影,缓存持续时间长,可以在网速允许的情况下适当增加并发数
        else if (dataType == videoFeeFilm && currentSpeed > 1.f) {
            maxConcurrentCount += 2;
        }
    }
    
    /// 性能检测方案1:
    /// 根据不同设备创建一个映射表,根据设备型号考虑是否对并发数进行降级。但这个方案并不适合,因为需要维护一个远端的映射表。
    /// 性能检测方案2:
    /// 根据当前cpu和运行内存的使用情况,进行对应的降级策略,这种方案比较通用,不需要维护映射表,并且可以实时反映出硬件的使用情况。
    
    CGFloat cpuUsage = [UIApplication sharedApplication].cpuUsage;
    int64_t memoryActive = [UIDevice currentDevice].memoryActive / 1024 / 1024;
    CGFloat batteryLevel = [UIDevice currentDevice].batteryLevel;
    
    /// cpu的取值范围是0.f ~ 1.f,如果是1.f则表示100%,但cpu经常会超频,在测试过程中短时间的超频是很常见的,170%的超频都是有的
    /// 发现即便到1.f界面也不会发生卡顿,如果发生超频,就对缓存进行降速
    if (cpuUsage > 1.f && maxConcurrentCount > 4) {
        maxConcurrentCount -= 2;
    }
    /// 可用运行内存等于-1,表示获取有问题
    else if (memoryActive == -1) {
        /// nothing
    }
    /// 可用内存小于100MB,对并发缓存数量进行限制
    else if (memoryActive <= 100.f && maxConcurrentCount > 4) {
        maxConcurrentCount -= 2;
    }
    /// 可用电量等于-1,表示电量获取有问题
    else if (batteryLevel == -1) {
        /// nothing
    }
    /// 电量到达临界值,对并发缓存数量进行限制,防止出现卡顿
    else if (batteryLevel <= 0.02f) {
        maxConcurrentCount -= 2;
    }
    
    /// 极端情况下的兜底策略
    if (maxConcurrentCount < 2) {
        maxConcurrentCount = 2;
    }
    
    /// 最后再设置并发值,防止一个方法里赋值多次
    self.maxConcurrentDownload = maxConcurrentCount;
}

收益

缓存速度提升

缓存加速的效果非常明显,我们先来看下加速前和加速后的视频对比,网络环境用的是家里的WiFi。大家可以看到加速前的平均速度为4.32 mb/s,加速后的平均速度为14.96 mb/s,加速后的效果非常明显的。

由于网络利用率的提升,缓存加速在WiFi环境下更为明显,WiFi网速快的情况下,甚至可以达到20+mb/s的下载速度。

额外收益

在开发缓存加速的过程中,也顺带解决了很多其他问题。

  1. 整体梳理代码逻辑,增加注释500+行,增加日志50+条。有助于后期代码维护,以及排查线上问题。
  2. 经过梳理代码,发现一些线上bug。例如:关闭开关后,应该弹窗打开系统网络弹窗,并且跳转系统设置页面。线上反应是弹出“打开搜狐视频应用内的流量弹窗”,点击后开始缓存,网都没有无法缓存。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容