抖音项目实现3: video微服务 | 青训营笔记

169 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天

目录导航:
1. 需求分析
2. 微服务的实现
3. 运行video RPC Server
4. 项目地址

1.需求分析

/douyin/feed/ 视频流在不限制登录状态下返回投稿时间倒序的视频列表,视频数由服务端控制,单次最多30个。因此用户鉴权不是必要的。

/douyin/publish/action/ 视频投稿,登录用户选择视频上传。对用户鉴权,如果成功,则将视频保存在服务器,并登记在数据库videos表中(其中需要生成视频封面以及访问视频和封面的url)。

/douyin/publish/list/ 发布列表,列出用户所有投稿过的视频。对用户鉴权,如果成功,则查询数据库,返回video list,因为包含作者信息,但是videos不存作者全部信息,因此还需要多表查询,响应数据慢,又访问视频url通过静态路由,因此对于响应速度有较高要求,是需要重点考虑的问题。

接口文档video.thrift如下:

namespace go user  
  
struct BaseResp {  
  1:required i32 status_code  // 状态码,0-成功,其他值-失败  
  2:string status_message // 返回状态描述  
}  
  
struct douyin_publish_action_request {  
  1:required string token // 用户鉴权token  
  2:required binary data // 视频数据  
  3:required string title  // 视频标题  
}  
  
struct douyin_publish_action_response {  
  1:BaseResp base_resp  
}  
  
struct douyin_publish_list_request {  
  1:required i64 user_id  // 用户id  
  2:required string token // 用户鉴权token  
}  
  
struct douyin_publish_list_response {  
  1:BaseResp base_resp  
  2:list<Video> video_list  // 用户发布的视频列表  
}  
  
struct douyin_feed_request {  
  1:optional i64 latest_time // 可选参数,限制返回视频的最新投稿时间戳,精确到秒,不填表示当前时间  
  2:optional string token  // 可选参数,登录用户设置  
}  
  
struct douyin_feed_response {  
  1:BaseResp base_resp  
  2:list<Video> video_list  // 视频列表  
  4:optional i64 next_time // 本次返回的视频中,发布最早的时间,作为下次请求时的latest_time  
}  
  
struct Video {  
  1:required i64 id // 视频唯一标识  
  2:required User author  // 视频作者信息  
  3:required string play_url  // 视频播放地址  
  4:required string cover_url  // 视频封面地址  
  5:required i64 favorite_count // 视频的点赞总数  
  6:required i64 comment_count // 视频的评论总数  
  7:required bool is_favorite // true-已点赞,false-未点赞  
  8:required string title // 视频标题  
}  
  
struct User {  
  1:required i64 id  // 用户id  
  2:required string name  // 用户名称  
}  
  
service VideoService{  
    douyin_publish_action_response PublishAction(1:douyin_publish_action_request req)  
    douyin_publish_list_response PublishList(1:douyin_publish_list_request  req)  
    douyin_feed_response  Feed(1:douyin_feed_request  req)  
}

2.微服务的实现

先利用kitex生成部分代码,主要编写dao层增删改查的功能,还有service层调用dao层操作数据库,最后改写handler文件,最后将服务注册到etcd上,注意不要和其他服务端口冲突。 生成视频封面时采用ffmeg抓取视频第一帧生成封面数据,代码如下:

func SaveCoverToResource(coverPath string, videoPath string) error {  
  
//make cover from video  
buf := bytes.NewBuffer(nil)  
err := ffmpeg.Input(videoPath).Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)"1)}).  
Output("pipe:", ffmpeg.KwArgs{"vframes"1"format""image2""vcodec""mjpeg"}).  
WithOutput(buf, os.Stdout).  
Run()  
if err != nil {  
return err  
}  
  
//save cover  
img, err := imaging.Decode(buf)  
if err != nil {  
return err  
}  
err = imaging.Save(img, coverPath)  
if err != nil {  
return err  
}  
  
return nil  
}

解决静态资源文件(视频文件)找不到404的问题,前端可以预加载静态资源,后端可以通过缓存中间件等快速响应查询,不用直接与数据库交互。如果实在不行就直接将视频上传到云存储或者自写文件服务器加快访问。

3. 运行video RPC Server

先查看docker中etcd容器是否开启,然后再输入以下指令:

sh build.sh
sh output/bootstrap.sh

终端提示server listen at addr=127.0.0.1:8890,已经开启了微服务,等待客户端链接。

4.项目地址

github仓库:github.com/LaiYuShuang…