201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

使用表格存储开发用户弹幕功能

目标

  • 使用表格存储(TableStore,原称OTS)实现视频直播的弹幕功能,通过TableStore存储弹幕,并在TableStore中检索最新弹幕实时显示到直播页面中。

准备工作

  • TableStore主页和控制台等

TableStore主页

TableStore控制台

AccessKey获取页面

TableStore文档和SDK

阿里云Code

  • 注意事项:预计耗费的费用

TableStore是一个按量计费的服务,根据存储量、读写吞吐量、外网流量等付费。具体的价格通过TableStore价格总览这个页面来获取。

TableStore目前每月赠送免费额度,包含1000万按量读、1000万按量写以及10GB存储。

考虑到TableStore的免费额度,在搭建视频网站过程中,除外网下行流量的费用外,将不会产生其他相关费用,因此课程中产生的总费用极低。

步骤

1. 创建TableStore实例。

打开TableStore控制台。点击右上角创建实例。

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

创建完成后可以看到我们刚刚创建的实例。

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

点击实例,可以进入实例详情页。

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

在实例详情页,我们可以查看该实例的访问地址,公网访问地址用于从公网访问,会收取外网下行流量费用,私网访问地址用于在阿里云的ECS*问,通过阿里云内网线路,不收取流量费用。

TableStore提供RESTful API接口,用户通过TableStore提供的各语言SDK进行数据操作以及表操作,在使用SDK时需要指定实例访问地址、AccessKeyId、AccessKeySecret、实例名。

2. 创建数据表。

在实例详情页,我们可以创建数据表(通过SDK也可以建表),如下图所示。

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

我们创建了名为danmaku的一张表,用于存储弹幕。预留的读写吞吐量全部设置为0,即不预留,完全采用按量计费的模式(预留会按照预留吞吐量计费)。

创建数据表时,设置表的主键非常重要。TableStore中的一行由主键列和属性列构成,主键列最多可以有4列,他们按照顺序构成一个主键,主键唯一的决定一行,不会有重复,TableStore会按照主键的大小对行进行排序。属性列目前最多可以有1024列,每行的属性列列数和列名都可以不同,而每行的主键列的列数和列名都是相同的。因此TableStore是半结构化类型的数据库。

这里我们设置三列主键分别为VideoID,Timestamp,UserID,分别代表视频的ID,弹幕发送时的服务端时间,弹幕发送者的ID。由于TableStore会按照主键排序,因此同一个VideoID下,Timestamp是有序的,可以使用TableStore的范围读取功能从某个Timestamp开始获取更新的弹幕。

加入UserID作为第三列主键,可以保证主键的唯一性。我们使用毫秒单位的Timestamp,假如同一视频在同一毫秒有两条弹幕写入,这两条弹幕的主键会重复,其中一条会覆盖另一条。有很多方法可以保证主键的唯一性,我们采用的是加入UserID作为第三列主键的方式。

弹幕的内容我们保存在属性列中,属性列还可以保存很多其他信息。TableStore是半结构化类型的数据库,因此可以动态的增加属性列,非常灵活。

3. 使用TableStore PHP SDK进行数据读写。

  • 整个过程如下图所示,网页端在发送或获取弹幕时先访问php服务端,由php服务端调用TableStore的php sdk进行数据读写。

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

我们使用了两个接口,PutRow和GetRange,结合我们建表时设计的主键,数据读写的示意图如下:

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

写入一条弹幕:VideoID、UserID、Text由网页端提供,Timestamp使用服务端当前时间,调用PutRow接口写入。

获取最新弹幕:网页端提供VideoID,并提供一个startTimestamp,表示从该Timestamp开始读取,调用GetRange接口,设置起始主键为(VideoID, startTimestamp, ""),结束主键为(VideoID,服务端当前时间,"")。

好,下面进入具体的代码部分,我们在阿里云Code上查看代码,我们需要打开“demo/DanmakuDataModel.class.php”这个文件。

  • 准备配置,包含endpoint(实例访问地址)、instanceName(实例名)、AccessKeyId和AccessKeySecret。

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

在上图中的位置设置相关配置。

  • 根据配置构造otsClient,通过otsClient调用OTS的API。

代码如下:

public static function init() {
     self::$otsClient = new OTSClient(array(
                    'EndPoint' => OTS_END_POINT,
                    'AccessKeyID' => OTS_ACCESS_KEY_ID,
                    'AccessKeySecret' => OTS_ACCESS_KEY_SECRET,
                    'InstanceName' => OTS_INSTANCE_NAME
                 )); 
} 
  • 将弹幕写入TableStore

我们通过TableStore的PutRow接口,将一条弹幕写入TableStore的数据表中。

在使用PutRow接口前,强烈建议用户阅读我们的API参考手册

上面我们建表时设置的主键列分别为VideoID、Timestamp、UserID,我们设置对应的主键值构造出"primary_key", 然后将其他的一些信息存在属性列中,即构造attribute_columns。

代码如下所示:

public static function put($danmaku) {
    $request = array(
            'table_name' => self::$tableName,
            'condition' => 'IGNORE',
            'primary_key' => array(
                self::$pk1 => $danmaku["VideoID"],
                self::$pk2 => $danmaku["Timestamp"],
                self::$pk3 => $danmaku["UserID"]
                ),
            'attribute_columns' => array(
                'text' => $danmaku["text"]
                )
            );
    $response = self::$otsClient->putRow($request);
    return true;
}

注意到$request中还有一个参数为condition,这个是设置行的存在性条件,我们在此设置为IGNORE,即不关心该行在写入前是否存在。

  • 通过TableStore读取弹幕

读取弹幕时我们使用TableStore的GetRange接口,该接口设置一个起始主键和一个结束主键,读取该范围内的行。

同样,我们首先阅读API参考手册,对GetRange接口有一个了解。

前端的视频页面保存最后一条弹幕的Timestamp,获取弹幕时将该时间戳传给PHP端,希望获取该时间戳后的最新弹幕。PHP端根据该时间戳构造起始主键,根据当前时间构造结束主键,然后调用GetRange接口进行查找。

由于起始主键和结束主键中的数据可能非常多,一次GetRange调用可能无法取得全部数据,当遇到这种情况,GetRange会返回next_start_primary_key,表示要扫描的下一个主键的值,可以将这个next_start_primary_key设置为起始主键进行下一次查询。

代码如下:

public static function get($conditions) {
    $startPk = array(
            self::$pk1 => $conditions["VideoID"],
            self::$pk2 => $conditions["StartTime"],
            self::$pk3 => ""
            );
    $endPk = array(
            self::$pk1 => $conditions["VideoID"],
            self::$pk2 => (int)(microtime(true) * 1000),
            self::$pk3 => ""
            );

    $request = array(
            'table_name' => self::$tableName,
            'direction' => 'FORWARD',
            'inclusive_start_primary_key' => $startPk,
            'exclusive_end_primary_key' => $endPk,
            'limit' => self::$getRangeLimit
            );

    $list = array();
    while (true) {
        $response = self::$otsClient->getRange($request);
        foreach ($response["rows"] as $item) {
            $list[] = array(
                    'VideoID' => $item["primary_key_columns"]["VideoID"],
                    'Timestamp' => $item["primary_key_columns"]["Timestamp"],
                    'UserID' => $item["primary_key_columns"]["UserID"],
                    'text' => $item["attribute_columns"]["text"]
                    );
        }
        if (count($list) >= self::$getDanmakuLimit) {
            break;
        }
        if ($response["next_start_primary_key"] == NULL) {
            break;
        } else {
            $requset["inclusive_start_primary_key"] = $response["next_start_primary_key"];
        }
    }
    return $list;
}

4.与前端视频页面进行交互。

  • 弹幕效果:

201604深圳云栖大会Workshop - 使用表格存储开发用户弹幕功能

上一篇:OpenStack 在CoreOS的新的基于Kubernetes的Stackanetes项目上得到了“自愈”能力


下一篇:数字化首个安全生产标准,阿里云联合信通院发布《基于云计算的数字化业务安全工程要求》