藏小姐姐的历史

Kiyor | Created: 04-01-19 13:42:49, Last Update: 04-11-19 19:32:59




更新

2019-04-12 02:32:16.952234857 +0000 UTC

发现digitalocean的limit available非常坑, 居然api挂了, 发ticket超过1天不回, 资源形式迁移至单台5刀设备, 开发一个cpu监控, 打算在忙时可以自动伸缩. 依赖为ffenc-server使用rabbitmq接受encode api请求. 已开发/迁移完成.


这个项目最初应该是在2014年, 最开始只不过就是通过本地电脑加硬盘的最简单管理, 从2014年开始把视频开始往服务器发展.

一开始主要解决的是这几个问题.

  1. 下载视频.
  2. 所有视频可以在想被访问的时候能够被访问.
  3. 对于一些番剧可以自动生成播放列表.
  4. 对于使用外挂字幕的mkv格式可以自动提取字幕并使用播放器播放.

问题1的解决方案最初是VNC加安装带有API功能的JDownloader满足标准http下载, 以及安装transmission daemon满足bt下载.

对于问题2主要是当时还会遇到一些需要转码才能够播放的视频比如mkv格式还有部分wmv和avi格式. 番剧生成列表其实是懒的一个一个播放, 字幕的需求倒是真的是刚需, 毕竟动漫花园的全集资源mkv居多.

于是后来就开发了playlist这个项目, 项目实现功能如下:

  • cronjob检查特定目录下的所有文件, 当被监测到可以被转换格式的视频时做转码.
  • 如果文件夹内的文件被检测出为带有序列号的文件时自动生成播放列表.
  • 访问使用nginx加fancyindex以及base auth和根据IP做whitelist的功能.

就这样的结构修修补补一直用到17年, 期间加了一个对图片文件夹生成一个html页面的图片(漫画)浏览页面生成器. 另外也经历了JDownloader基本失效迁移到了JDownloader2.

然后遇到了一个痛点.

  • 普通的file system无法打标签和label. 文件过多后管理混乱.
  • 有时一些压缩文件有自己的密码, 解压需要登陆到设备完成, 不太方便.

针对以上两点就在17年开发了KFS, 这个软件基本上是在golang原生的ServeFiles基础上进行扩展, 做了页面优化. 功能点如下:

  • 从界面上可以直接操作删除, 特殊密码解压.
  • 当文件夹内有图片文件时可以通过一键自动生成html浏览器页面.
  • 界面中打tag, 打label(颜色), 实现方式是在上层目录下生成一个隐藏文件存储文件夹内文件. 当KFS做渲染页面前读取.
  • 所有操作用querystring解决. 避免使用任何JavaScript.

由于对文件管理的方式有了优化, 下载速度就快了很多, 用了一段时间又发现了问题.

  • 一段时间内下载任务过多的时候下载服务商会强制修改密码, 新密码以email形式发送到个人邮箱.
  • JDownloader2修改密码需要登陆VNC.
  • JDownloader2处理大量task时管理上容易出错, VNC和webUI都操作不方便.

既然问题都出在下载器JDownloader2上, 于是就开发了一个叫kdown的程序, 本来是想使用aria2c解决的, 但由于下载站需要登陆, 下载器也不是特别难写, 所以就自己写了一个.

kdown的主要特点如下:

  • 登陆下载站.
  • 多线程下载文件, 使用range请求下载.
  • 下载完进行文件拼接并校验下载站提供的md5.
  • 如果文件为压缩文件或多part压缩文件则自动解压并删除压缩文件.

下载速度快还有一个急迫需要解决的问题, 越来越多的文件存在哪儿? 问题很容易解决, 云, S3!!! 等下, S3很贵…于是我选用了便宜的S3方案, wasabi. 但我仍然上传视频至S3, 因为S3可以直接调用SQS和Lambda做视频转图片, 做缩略图. 其实可以不需要的, 可以在上传前程序内完成, 当时这样的设计只是因为想试试使用Lambda.

于是开始着手新的软件开发s3up, 主要特点如下:

  • 本地文件浏览器可以设置上传到s3
  • 可以设置文件的各种信息, 文件key以加密后的md5值, 并对其像nginx hash一样做/a/bc/文件夹式. 防猜测文件路径.
  • 放弃playlist程序, s3up承担转码任务, 当时已经没时间看番了, 所以舍弃了字幕和序列播放器需求.
  • 还开发出了上传和转码的前端显示进度条, 通过读取ffmpeg的输出转换成比例给予前段.

之后又发现了问题, 下载速度快, 转码速度成为瓶颈.

于是开发了一套基于容器的分布式转码程序ffenc, 特点如下:

  • 程序分成两部分, ffenc-server, ffenc-client.
  • ffenc-server承担任务分发, 获取任务后对文件进行视频分割, 音频单独分离, 分割文件放置在nginx目录下.
  • ffenc-server发布任务给rabbitmq.
  • ffenc-server承担client对mysql的api操作请求.
  • ffenc-client获取rabbitmq中的任务.
  • ffenc-client转码后上传至nginx目录下.
  • 当所有子任务完成后ffenc-server对整个文件进行合并.

此程序至今仍会发生有部分格式不支持的问题, 只能提供容错解决.

单独分离出了转码就有意思了, 所有之前做的程序都可以直接用api去调用大量client进行转码. 比如之前做的kdown.


终于来到了一个分水岭, 这个分水岭就是一台8T的服务器终于还是塞满了, 来不及审核视频做上传了. T_T

于是新的方案来临, 以上所有提到的程序全部kubernetes化. K8S化其实在之前的设计中一直有一个缺陷, 如果要做一个纯分布式程序, 基本上所有的连接器都需要用像rabbitmq或者kafka. 然而我只在ffenc里使用了rabbitmq. 如果需要做一个纯分布式程序, 需要改动的结构太多了, 所以基本上只能选用单个pod的statefulset的方式部署known, s3up, ffenc-server程序.

改进是, kdown不使用本地存储, 当kdown下载后自动上传至S3, 把S3当作无限容量的存储, 内网不消耗流量. s3up本来是一个本地文件浏览器, 现在变成了S3文件浏览器, 审核后的文件可以直接上传至wasabi, 上传任务其实就是先下载到本地(内网通信), 再上传至目标S3. ffenc-server同样接受到的转码任务支持S3文件类型的任务, 先下载文件再发布任务给rabbitmq. 可以看到完全依赖内网并且还要以外网去上传至别家的S3, 成本控制的原因导致选择只能是digitalocean.

还需要提一下下载任务发布的小程序是用过监视mac上的剪切板, 当发现固定字符串的时候请求一个api到一个服务, 此服务会解析剪切板中的url并对url中的支持链接进行抓取, 自动生成任务后发送至kdown.

最近遇上的一些问题:

  • 单机本身机器性能强劲, 所有容器化的程序也有非常大的临时空间, 容错非常高, 换成kubernetes后会发现对于所有pod都必须严格定义cpu和ram的使用量, 稍不合理就会导致资源浪费或者程序OOM. 包括临时空间需要使用的是云硬盘, 云硬盘需要定义空间, 以前没写硬盘没空间的容错, 导致当一些错误发生云硬盘直接没空间. 很多之前没考虑到的错误频繁发生.
  • 分布式程序需要一根“总线”, 这根“总线”一般使用kafka或rabbitmq之类的程序, 当前只使用了基本的rabbitmq, 就已经发现了当出现一些错误的时候要清理特定的queue不是呢么容易. 这需要对这种消息类服务有更多研究, 并且使用dead letter等特性. 如果不使用这根“总线”则很难完全分布式化.
  • 下载, 转码都快, 来不及审核…

未来的计划:

  • 解决“总线”问题, 做到完全分布式.
  • 对于ffenc所创建的临时文件也放入S3, 但这个做不做与digitalocean的S3流量费和服务器流量费和预算更有关系一些.
  • 开发一个程序做到可以部分内容完全离线化, 程序可以掌握本地硬盘的信息. 硬盘以插拔式3.5寸HDD为主, 满了就换.
  • 优化界面, 上线…


Category: none