腾讯云直播开发日记 (二)
上篇文章完成了直播的简单业务,我们可以慢慢将这个直播进行完善, 例如 附近直播
直播礼物
直播回放
, 当然实际业务要比我说的复杂,博主这里提供一个思路
附近直播
现在社交附近的人都是基本功能, 所以我们的直播也不例外, 本身附近的人功能就不复杂, 只不过是选择哪种方式来做合适罢了。要做这个附近的人,首先要收集用户的经纬度存放到数据库,也就是我们的数据表会变成这样
参数名 | 说明 |
---|---|
id | 自增主建 |
user_id | 用户ID |
live_url | 播放地址 |
obs_url | 推流地址 |
avatar | 直播封面 |
title | 直播标题 |
status | 直播状态 是否在播 |
lat | 纬度 |
lng | 经度 |
city | 给用户看的位置信息 |
获得了经纬度后,我们就可以通过技术手段获取附近的用户,按照位置信息、 热度等排序展示给用浏览了
常见附近的人处理方式有:
Mysql实现附近的人
mysql
实现附近的人也分2种方案
- 每次都通过函数计算
这种就需要计算,消耗大一点,但是数据量小直径忽略,业务最大,开发效率最大
这里给出一点代码,大家可以看看
代码语言:javascript复制// 6371是计算公式的公里 英里是3959
$distanceRaw = <<<SQL
(
6371*acos(
cos(radians(%s))
*cos(radians(lat))
*cos(radians(lng)-radians(%s))
sin(radians(%s))
*sin(radians(lat))
)
) AS distance
SQL;
$data = LiveRoomModel::query()
->where(['status' => 1])
->having('distance', '<=', $km)
->forPage(
$data['page'], $data['size']
)
->orderBy('distance')->get(
[
'id',
'title',
'room_avatar',
'city',
'status',
DB::raw(
sprintf(
$distanceRaw, $data['lat'], $data['lng'], $data['lat']
)
)
]
)->toArray();
还有另一种方式, 设置 geometry
地理空间类型字段, 可以利用 mysql
的空间函数 ST_Distance_Sphere
进行计算得出距离, 以米为单位
- 利用
GeoHash
减少计算
GeoHash
算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离会很接近。当我们想要计算附近的人时,首先将目标位置映射到这条线上,然后在这条一维的线上获取附近的点就ok了。
我们使用对经纬度进行 geohash
算法计算得出hash
值, 存入数据库使用like
查询, 查出附近的人进行二次计算得出距离即可
Redis
Redis
中处理这些地理位置坐标点的思想是:
Redis
中经纬度使用52位的整数进行编码,放进zset
中,zset
的value
元素是key
,score
是GeoHash
的52位整数值。在使用Redis
进行Geo
查询时,其内部对应的操作其实只是zset(skiplist)
的操作。通过zset
的score
进行排序就可以得到坐标附近的其它元素,通过将score
还原成坐标值就可以得到元素的原始坐标
二维平面坐标点
一维整数编码值
zset(score为编码值)
zrangebyscore(获取score相近的元素)
通过score(整数编码值)反解坐标点
附近点的地理位置坐标
使用 redis geo
指令就可以实现了, 使用时务必再次想起,它只是一个普通的zset
结构。
georadiusbymember
查询指定元素附近的其它元素geodist
计算两个元素之间的距离
在一个地图应用中,车的数据、餐馆的数据、人的数据可能会有百万千万条,如果使用 Redis
的 Geo
数据结构,它们将全部放在一个 zset
集合中。在 Redis
的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key
的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key
对应的数据量不宜超过 1M
,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。
所以,这里建议 Geo
的数据使用单独的 Redis
实例部署,不使用集群环境。
如果数据量过亿甚至更大,就需要对 Geo
数据进行拆分,按国家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 zset
集合的大小。(注意:zset
集合大小,进行合适地切分)
ElasticSearch
这个效率比较高,也是应用比较多,我们也介绍一下
es
也有地理位置相关的数据类型, 例如: geo_point
geo_shapes
那这两种有一定区别, 我们做一个简单的附近的人采用 geo_point
即可, geo_shapes 纯粹是用来过滤的
- geo_point
用于计算距离、排序、打分以及聚合, 有时候距离并不是影响排序的唯一因素, 可能和热度, 好评也相关, 所以打分也是一个很重要的功能, 如果大家的排序多样化 可以选择 es
- geo_shapes
geo_point
和geo_shape
的最大区别是: geo_point
表示一个点;geo_shape
则表示有多个点连成线组成的形状。 学过数学的肯定很容易理解。
他的主要作用就是: 判断查询的形状与索引的形状的关系
- 查询的形状与索引的形状有重叠 或者不重叠
- 索引的形状完全被包含在查询的形状中, 假如我们的想要查询落在一个凹多边形内的点, 使用
geo_point
类型的就满足不了我们的需求了
Geo-shapes
不能用于计算距离、排序、打分以及聚合。
MongoDB
也可以利用2d
索引, 本质上还是geohash
,附近的人只是一种基础功能, 做的时候考虑是否需要引入新技术, 新增成本是否能够接受? 我们不需要盲目使用各种各样的技术,根据业务挑选最合适的,就算技术最新又怎样,解决不了业务,导致项目延期,你这次采用的技术毫无价值
直播礼物
这个基本是必不可少的一项了, 做起来也不困难, 博主完整说一下, 这里包含一些前后端的交互
在开发APP
的过程中,需要在APP
中实现设计同学的UE
效果动画,一般都是通过代码实现的,当对于较复杂的动画时,例如直播中刷礼物时的动画,这时利用代码实现会比较复杂。而且Android
和iOS
两端不好统一效果,如果用gif
图片来实现的话,在图片大小和动画帧数之间很难权衡。而且会导致内存吃紧。为了解决这样的问题,介绍两款实现复杂动画的开源库:Lottie
和SVGA
。
- Lottie
地址: https://github.com/airbnb/lottie-ios
爱彼迎
的好东西, 别说, 他们APP
效果很不错, JS
代码风格也是业内标杆, 我以前严格要求项目组按照这种风格编码.
但是这个对平台有限制,iOS 8.0
以上,Android API 14
以上。交互动画不可行,主要是播放类型动画。开发成本也比较低, 设计师导出json后,开发同学只需引用文件即可。
- Svga
地址: http://svga.io/
动画设计师专注动画设计,通过工具输出 svga
动画文件,提供给开发工程师在集成 svga player
之后直接使用。方便,跨平台好, 我们公司选择的就是这个, 我们还有一个微信小程序, 当时小程序
对Lottie
支持不太好,并且公司前端技术也比较倾向于这个
然后我们说一下后端, 如果按照数据驱动开发的方式的话, 我们需要将礼物相关表建立一下, 例如: 礼物表、礼物类别、直播间礼物打赏日志、其他用户消费日志等等
这里我说一下礼物表, 基本字段
参数名 | 说明 |
---|---|
id | 自增主建 |
title | 礼物名称 |
image | 礼物图片 |
svga | SVGA的URL |
price | 礼物价值的虚拟币 |
is_animation | 1特效 0 为特效 |
time | 特效持续时间 s为单位 |
sort | 礼物排序 |
礼物如果需要抽点的, 做一个系统配置。看到这,我相信大家应该都有一个大概了, 怎么做心里应该有点数了, 还有一个没说到的就是, 礼物发送之后是需要让所有人看到的, 这样我们就需要做消息广播了, 这个可以使用 IM
实现, 后面再说
直播回放
因为直播是在线看的, 用户又不一定每次都有时间在某个点去看, 所以回放也变成了一个必不可少的功能。开通云点播,在云直播的功能配置里面有录制配置,每次直播完后的视频会保存到云点播里面 那这个视频是需要和用户绑定的, 所以腾讯这边提供了回调给我们,当直播断流时会回调我们的接口,将本次录播的文件等信息传递给我们,我们进行保存。 那么还可以利用点播做一个类似抖音的东西, 我们可以让用户上传视频到云点播、直播视频保存在云点播,做一个视频列表,向下滑动来观看,只要将视频和用户关联起来就可以了。可以做的很多,就不一一介绍了
这个也比较简单,看看文档就行,所以不做过多的介绍,就到这了,下一篇继续介绍直播聊天室的实现