布景

视频缓存已经成为各大视频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

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

视频缓存加速,2.5倍优化

测验数据

测验办法

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

测验办法,在同一时间缓存同一剧集,相同清晰度,比照线上版别和缓存加快版别的不同,分别测验WiFi和流量环境。在测验阶段,设备一直在前台。

从数据来看,电影因为文件比较大,在网速快的状况下进步比较显着。电视剧因为网速刚上来就下载完了,数据没有这么显着,但也有50%左右的进步。

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

鉴于运用缓存功能的用户,大多数都是在WiFi环境下运用,所以主要还是以WiFi的数据为准。WiFi环境分别测验了公司WiFi,和我家里的WiFi,能够代表许多WiFi网络环境了。下面是不同网络环境下,屡次测验的均匀成果。

WiFi

通过屡次测验,均匀提速为2.35倍。

视频缓存加速,2.5倍优化

流量

通过屡次测验,均匀提速为1.50倍。

视频缓存加速,2.5倍优化

播映流畅性

为了避免缓存争夺过多网络资源,然后影响播映的流畅性,对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。例如:封闭开关后,应该弹窗翻开体系网络弹窗,而且跳转体系设置页面。线上反应是弹出“翻开搜狐视频使用内的流量弹窗”,点击后开端缓存,网都没有无法缓存。