抖声项目汇总

抖声项目汇总

单体架构仓库:https://github.com/Wuhlan3/dousheng

微服务架构仓库:https://github.com/Wuhlan3/kitexdousheng

一、简单介绍一下你的项目?

本项目的一些素材来源于字节跳动后端训练营,他们提供了一个抖声客户端,并且规范了可以实现的一些接口,包括用户登陆与注册、视频流、评论功能、点赞功能、关注功能等等。在训练营期间,我曾担任小组的队长,由于同小组有较多大一大二的同学,所以负责了该项目单体架构的设计、数据库表的设计、大部分接口的功能实现。最终该项目取得了较好的成绩。之后,我和舍友也尝试使用在青训营所学的知识,使用字节跳动的微服务架构KiteX框架来重新实现该项目,并且完善缓存机制、单元测试,完善了视频流的一些功能包括使用使用FFmpeg截取视频的封面、将视频通过存储桶来进行管理等等。

二、你主要做了哪些工作呢?

  1. 项目的整体设计(这主要是参考了一下KiteX框架下提供的一个笔记服务的样例,参照其文件的架构设计的)
  2. 数据库的设计和ER图的绘制也是我做的;
  3. 较完善的参数校验,对密码进行加密,使用JWT鉴权;
  4. 视频流的相关实现计包括将视频和封面上传到腾讯云COS对象存储桶,使用FFmpeg截取视频的封面;
  5. 使用Redis来减少访问数据库的次数

三、本项目你遇到的最大困难是什么,如何解决的?

我认为本项目最复杂的、也是最有必要认真实现的模块就是视频流的设计。

  1. 视频封面的获取,ffmpeg;
  2. 视频的存储方式——上传至腾讯云对象存储,并将对应的URL存放到数据库中(尝试过直接存储云服务器的本地文件夹中,但是由于带宽问题,且管理起来比较混乱,导致效果非常差)
  3. Redis的设计,涉及到两种数据结构ZSET和HASH,其中ZSET保存了视频的id和发布的时间latestTime(作为score)。在获取视频流的时候,我们首先通过获取最近发布的30个视频,之后根据视频ID再从Redis中获取视频相应的信息;优化之后,通过压力测试可以发现,报文返回的速度从100ms提升到50ms。
  4. 但是发现真正的卡顿问题出现在视频文件的传输上,考虑到我的云服务器是比较小型的服务器,2核2G的,带宽也比较有限,所以我尝试将视频上传到云服务器上。
  5. 同时使用了ffmpeg对视频进行处理,包括格式的转换,视频封面的获取等等。
  6. 最终使得客户端程序在运行的情况体验比较正常

四、数据库表是如何设计的?

主要涉及六张表,分别是user、relation、video、favorite、comment和publish。

其中,我认为最重要的两个实体是用户和视频,其他的表可以看作是这两者之间的关系。

用户表包括用户ID、账号、密码、关注数、被关注数等信息;

video表包括ID、视频封面的URL、视频URL、视频名称、上传者的ID、点赞数等信息;

....

此外,还对外键依赖、非空、唯一性等约束进行了设计。为了提高查询效率,适当的生成了索引。比如说,视频的上传者ID,点赞表中的 user_id和video_id作为联合索引。

六、整体架构是怎么设计的?

使用了Gin框架来开放HTTP端口,通过封装好的RPC客户端与微服务中的服务端进行通信。

RPC服务端通过接收客户端的请求,在各自的进程中完成业务逻辑和数据库的交互。

数据库层面使用了Redis缓存机制,使用MySQL进行持久化。

序列化手段一般包括JSON、ProtoBuf、thrift等。抖声客户端与服务器的交互直接采用的JSON,而RPC通信过程中使用了ProtoBuf来进行序列化。

JSON,ProtoBuf,thrift之间的区别是什么呢?

ProtoBuf无论是序列化和反序列化的速度,还是编码后的数据大小,都比JSON优秀很多,但是其可见性较差。因此在微服务之间通信时,protobuf 更合适,在公开 API 或与浏览器通信时JSON 与 xml 更合适。

protobuf与thrift的对比:

protobuf thrift
功能特性 主要是一种序列化机制 提供了全套RPC解决方案,包括序列化机制、传输层、并发处理框架等
支持语言 C++/Java/Python C++, Java, Python, Ruby, Perl, PHP, C#, Erlang, Haskell
易用性 语法类似,使用方式等类似
生成代码的质量 可读性都还过得去,执行效率另测
升级时版本兼容性 均支持向后兼容和向前兼容
学习成本 功能单一,容易学习 功能丰富、学习成本高
文档&社区 官方文档较为丰富,google搜索protocol buffer有2000W+结果,google group被墙不能访问 官方文档较少,没有API文档,google搜索apache thrift仅40W结果,邮件列表不怎么活跃

七、微服务架构相比于单体架构,优点体现在哪里?

微服务架构的优点如下:

  1. 单一职责。每个服务都有自己独立的业务逻辑,是一个高内聚、低耦合、单一原则的单元。
  2. 轻量级通信。服务之间用过轻量级的通信机制实现互联互通,通常是语言无关、平台无关的交互方式;
  3. 独立性。每个服务可以独立地进行开发、测试和部署;
  4. 进程隔离。每个服务高度自治,可以部署到不同的主机上。当其中一个服务挂掉时,不会影响其他服务。

使用微服务的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现公司跨团队的技术解耦。但是这样子,如果没有一个统一的服务框架——RPC框架,则各个团队需要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理等业务之外的重复技术劳动。统一RPC框架将上述的劳动进行了统一处理。

八、ETCD是什么?

ETCD是Go语言开发的一个开源的、高可用的分布式key-value存储系统。

微服务在ETCD注册中心中注册好自己的相关信息,之后api层可以通过ETCD来获取相应微服务的ip地址和端口号,从而发起RPC调用。

九、有没有对该项目的性能进行测试?

由于环境的限制,在两核2G的小型云服务器环境下,在30秒内5000个客户端的情况下,可以处理40000个请求。之后还会继续完善测试。

十、JWT相关原理

是作为中间件来使用的,大部分的HTTP接口都需要JWT校验通过之后,才能够进行下一步的业务逻辑处理。

JWT的实现原理:

  1. 用户登录的时候,会将账号和密码发送给服务器;
  2. 服务器验证账号密码的有效性后,会返回签名后的token给客户端;
  3. 客户端将token存储在本地存储中
  4. 之后客户端的请求,都应该携带上token,服务端在对token解码之后,判断其解码的有效性,从而认证客户的身份。

签名的过程:

首先JWT的结构如下:

  • 头部:包含了基本信息;基于Base64编码规则
  • 荷载:包含了签发者、用户、接收方、过期时间等等;基于Base64编码规则
  • 签名:使用HS256算法来对(头部和荷载)进行加密。(作用是防止篡改)

十一、RPC的原理

参考:https://wuhlan3.gitee.io/wuhlan3/2022/08/05/%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%97%AE%E9%A2%98%E6%B1%87%E6%80%BB/

十二、Gin有什么特点?

  1. 路由
  2. context上下文,方便传递

十三、你的项目中使用到了什么设计模式?

  1. 在repository层使用了单例模式。比如说我们给UserDao绑定了Query、Update等方法,在每次调用的时候,我们都返回userDao这个单例对象,而避免重复生成,消耗额外的资源。(对于每个线程,可共享一个实例)

  2. 在service层,我们使用了简单工厂模式,比如说对于userlogin这个模块,我们定义了一个UserLoginFlow的对象,每次调用它的方法,我们首先要根据所需的参数new出这一个对象,之后做参数校验、逻辑处理等工作。简单工厂模式可以确保我们创建的实例具有需要的参数,进而保证实例的方法可以按预期执行

    1. 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;

    2. 简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。

    3. 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量

    4. 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

十四、代码行数

1
2
3
4
//算上kitexgen自动生生成的有9218行
find . "(" -name "*.go" ")" -print | xargs wc -l
//如果不算,有3702行
find cmd config pkg "(" -name "*.go" ")" -print | xargs wc -l

十五、怎么测试抖音

基本思路:

  1. 回答功能层面的测试点(最重要的)
  2. 之后拓展到 UI测试、兼容性测试、易用性测试、可移植性测试、性能测试等等。

功能测试的中的概念就在于寻找输入口:

  1. 上拉测试,视频是否加载、用户名称、title、点赞数、收藏数是否符合预期
  2. 下拉测试;
  3. 多次上拉,查看是否不同的视频
  4. 多次上拉,查看视频是否按照规定的顺序切换:(比如我的项目中采用的是上传时间)
  5. 点赞,查看点赞数是否增加;在关闭程序后,再次查看该视频,看点赞数是否持久化。
  6. 关注,测试过程与点赞类似。但是除了查看我的关注数是否增加外,还需要查看对方的页面,被关注数是否增加。同时还要查看关注和被关注列表
  7. 关闭App后,视频是否会重复推荐,是否影响正常的体验。

UI测试:UI是否维持它原有的状态;界面是否美观、颜色搭配是否合理、布局是否合理、按钮大小位置是否合适、文字大小颜色搭配是否合适。

兼容性测试:在不同的手机型号、不同的分辨率下、不同的操作系统,测试效果如何。

易用性测试:是否由明显的提示,用户是否可以在点击三次鼠标内就达到目的;评论功能的复制粘贴。

性能测试:视频加载的速度。视频上传的速度。

安全性测试:登录验证码,记住密码,自动登录,找回密码,SQL注入问题,报文是否加密

中断测试:退出后再进来

网络测试:测试下在弱网,无网,4G,5G网络下面,这个功能是否还正常,有对应处理,比如无网就要提示等等。(有用过一些工具比如fiddler去模拟弱网等场景。)

十六、项目中有没有使用到事务?

有。Gorm中自动开启

十七、Docker有什么特点?

Docker包括三个基本概念:

  1. docker镜像:就相当于是一个 root 文件系统。
  2. docker容器:镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  3. docker仓库:仓库可看成一个代码控制中心,用来保存镜像。

docker的三大底座:

  1. namespace 命名空间:容器隔离的基础,保证A容器看不到B容器.

  2. cgroups 控制组:主要用到的cgroups子系统:cpu,blkio,device,freezer,memory

    实际上 Docker 是使用了很多 Linux 的隔离功能,让容器看起来像一个轻量级虚拟机在独立运行,容器的本质是被限制了的 Namespaces,cgroup,具有逻辑上独立文件系统,网络的一个进程。

  3. unionfs 联合文件系统:是一种轻量级的高性能分层文件系统,支持将文件系统中的修改进行提交和层层叠加,这个特性使得镜像可以通过分层实现和继承。

十八、Docker和虚拟机的对比

  1. 虚拟机需要模拟整个机器包括硬件、库、一个完整的用户操作系统。而Docker是与宿主机共享硬件资源及操作系统,可以实现资源的动态分配。
  2. 虚拟机的启动在分钟级别、docker的启动在秒级别可以做到快速部署
  3. docker需要的资源更少,在操作系统级别进行虚拟化,容器与内核的交互几乎没有额外的损耗
  4. docker的隔离性更弱、安全性也更弱。属于进程之间的隔离。虚拟机可实现系统级别的隔离。docker与宿主机共享内核、文件系统等资源,更有可能对其他容器、宿主机造成影响。

十九、Dockerfile怎么写

二十、密码怎么加密的,使用了什么算法

使用的是bcrypt中的一个库函数。就是一个加盐的过程。先生成一个随机数salt,然后和password一起进行hash。

对同一个密码,每次生成的hash不一样,这是因为hash中包含了salt(hash产生过程:先随机生成salt,salt跟password进行hash); 在下次校验时,从hash中取出salt,salt跟password进行hash;得到的结果跟保存在DB中的hash进行比对,compareSync中已经实现了这一过程:bcrypt.compareSync(password, hashFromDB);

二十一、登陆方式

cookie和session的查缺补漏

JWT加密方式:HS256,是对称加密算法


抖声项目汇总
https://wuhlan3.gitee.io/2022/08/07/抖声项目问题汇总/
Author
Wuhlan3
Posted on
August 7, 2022
Licensed under