用 LFS 做极简高效的流媒体服务

原创
2015/09/07 15:20
阅读数 6.6K

    示例可在:github git@osc 找到,包含一个详细的图片服务器

    图片服务演示(简单部署了 php 的服务):

    浏览图片http://lfs2-ikcourage.myalauda.cn/testimage/image.php?type=read&id=1

    上传图片:http://lfs2-ikcourage.myalauda.cn/testimage/upload.php  (图片会自动周期性删除)


    先做一个音乐、视频、图片等媒体文件的上传和下载示例。都只需要一行。

FileInputStream inputStream = new FileInputStream(file);
fileId = LFS_Stream.writeStream(FILE_NAME, fileId, inputStream, file.length());

    OK,一个媒体文件上传成功后会返回一个文件 ID。

    即使是一个比较大的视频,比如大于 10G,也依然只有这一行代码,并不需要做切片存储,并且无需担心内存使用。(大文件的上传也变的如此简单)

    下载:

//读到 readStream 中
LFS_Stream.readStream(FILE_NAME, fileId, readStream);

    没错,就是这一行啦,根据文件 ID 读取文件,把数据通知给 readStream。

    那么,我们来看看 readStream 做了什么。(这就是一个完整的媒体服务的示例)

IReadStream readStream = new IReadStream() {
    public boolean init(long fileId, int size, long sizeTotal, long sizeTotalRead, long offset) {
        response.setIntHeader("Content-Length", (int)sizeTotalRead);
        response.setHeader("Cache-Control", "max-age=604800");
        response.setIntHeader("Etag", 0);
        return true;
    }

    //参数好多啊,不要被吓到了,只有前两个是你需要用的
    //其他的只是为了避免全局变量而已(如果需要的话,所幸,绝大多数场景都不会需要)
    public boolean parseData(byte[] b, int bytesAvalibale, int size, long sizeTotal, long sizeTotalRead, long sizeTotalReaded, long offset) {
        try {
            //这里应实现自己的数据输出,比如输出到 http
            response.getOutputStream().write(b, 0, bytesAvalibale);
            return true;
        } catch (Exception e) {}
        return false;
    }
};

init 只会在 parseData 前调用一次,用来获取文件的真实大小,比如我们可能需要为 http 添加 Content-Length 的头等。

parseData 每次都会调用,把缓冲中的数据输出到 http 的输出流中,bytesAvalibale 是缓冲中的有效字节大小。

    到这里你会发现,parseData 中是流式输出数据的,所以这保证了音乐、视频等流媒体的流畅度,并且也有效降低了服务器的内存占用。因为缓冲的大小是非常小的,你可以理解为 Socket 的缓冲大小,并且可调节,默认大小 2K(注:不是带宽的大小,这是一个远高于带宽的值)。

    这意味着一台服务器,即使提供视频服务也游刃有余。1W 人同时观看视频只需要不到 20M 的内存(资源过剩的浪费)。


    既然是流媒体服务(图片也是,在浏览器中快速刷新,会看到图片一点点的渲染),那么断点下载很重要,断点上传也很重要。

    断点下载:

//多了两个参数
LFS_Stream.readStream(String fileName,
    long fileId,
    IReadStream readStream,
    long offset,
    long sizeTotalRead);

    还是那一行,只不过多了一个偏移和读取大小而已,很简单不是么。

    断点上传:

//多了两个参数
LFS_Stream.writeStream(String fileName,
    long fileId,
    InputStream inputStream,
    long sizeTotalWrite,
    long offset,
    long sizeTotal);

sizeTotalWrite 是要写的大小,sizeTotal 是文件的总大小。

这句话的含义是:把文件的总大小设置为 sizeTotal,并且在 offset 处写入 sizeTotalWrite 大小的内容。

    上传下载就是如此的简单。


    LFS 的启动

    首先从 github 获取一个 LFS

    然后以守护模式运行 LFS --dir [存储目录] --daemon

    这就好了

    最后,如果需要自定义文件名的话,可以使用 LFS 的索引(即:key, value)。参考上一篇内容。


展开阅读全文
打赏
19
255 收藏
分享
加载中
请发下 php的示例 参考,谢谢!
tanetbls@126.com
2015/09/28 18:00
回复
举报

引用来自“然乌”的评论

引用来自“然乌”的评论

至少给个安装使用教程之类的嘛

引用来自“Courage”的评论

直接启动就好,或者看 github 里的指南
在linux下面各种缺东西 在window下面直接内存错误 可以加qq聊么

ewfewfewfe
2015/09/22 10:13
回复
举报
Courage博主

引用来自“然乌”的评论

至少给个安装使用教程之类的嘛

引用来自“Courage”的评论

直接启动就好,或者看 github 里的指南

引用来自“然乌”的评论

在linux下面各种缺东西 在window下面直接内存错误 可以加qq聊么
linux 下都是基础的库,应该是版本不符合。windows 下内存错误?是缺少 dll 吧?
2015/09/11 13:48
回复
举报

引用来自“然乌”的评论

至少给个安装使用教程之类的嘛

引用来自“Courage”的评论

直接启动就好,或者看 github 里的指南
在linux下面各种缺东西 在window下面直接内存错误 可以加qq聊么
2015/09/10 19:45
回复
举报
Courage博主

引用来自“然乌”的评论

至少给个安装使用教程之类的嘛
直接启动就好,或者看 github 里的指南
2015/09/10 16:42
回复
举报
至少给个安装使用教程之类的嘛
2015/09/10 16:16
回复
举报

引用来自“purple_grape”的评论

LFS名字已经被人占了,换个名字吧
Linux From Scratch 好流行的发行版本,Hacker的最爱
2015/09/08 19:28
回复
举报
Courage博主

引用来自“mxbyshell”的评论

不开源,无明确发展、演进计划,详细架构,不敢使用。
架构、计划在这:http://my.oschina.net/courage/blog/474323
2015/09/08 18:45
回复
举报
不开源,无明确发展、演进计划,详细架构,不敢使用。
2015/09/08 17:11
回复
举报
Courage博主

引用来自“zhaoyou”的评论

流媒体服务的瓶颈是在文件系统吗?22
不是说瓶颈在文件系统,这只是用来做一个流媒体服务而已,与其说比其他系统更快,其实我更喜欢的是单个文件 ID 可以存储不断增长的数据(增量)
2015/09/08 16:54
回复
举报
更多评论
打赏
29 评论
255 收藏
19
分享
返回顶部
顶部