第7章内容发布系统——7.4 内容的全生命周期管理设计

第7章内容发布系统——7.4 内容的全生命周期管理设计
John Yaml7.4 内容的全生命周期管理设计
本节讲解内容的全生命周期管理设计,前面产生的各种问题都会在本节得到解答,比如:内容元信息的存储为什么使用两张数据表,数据表每个字段的实际用途是什么,如何处理内容审核结果,等等。
7.4.1 内容的创建设计
当创作者在产品客户端新创建了一条内容并准备将其提交到内容发布系统的服务端时,我们应该怎么处理这个请求?
- 首先,客户端需要进行内容数据类型的识别和归类。如果新创建的内容包含长文本图片,则需要先将它们以文件形式上传到分布式对象存储系统中。如果分布式对象存储系统成功存储了这些文件,则会返回长文本URI和图片URI;如果新创建的内容包含视频,则由于涉及必要的视频编解码,所以需要先将本地视频文件上传到由专门的视频团队开发的视频服务中(这个服务会先对视频进行转码,然后把结果存储到分布式对象存储系统中),并由视频服务返回一个唯一的视频ID代表这个视频,我们可以根据这个视频ID从视频服务中获取视频。
- 然后,在将这些特殊文件存储到服务端后,客户端会收到服务端的响应,接收到长文本URI、图片URI和视频ID。
- 最后,客户端携带创作者信息、内容可见性设置、内容短文本及服务端返回的长文本URI、图片URI和视频ID再次请求服务端。此时,我们在内容发布系统中为此内容创建元信息:通过分布式唯一ID生成器生成一个全局唯一的item_id来标识这条内容,并填充item_info 表的item_id、creator_id(创作者ID)、visibility(内容可见性)、create_time(内容创建时间)和 update_time(内容变更时间)字段。
关于是否直接发布内容的重点来了:如果内容创作者拥有大量粉丝,或者其近期被举报多次,或者其近期发布的内容总是被审核拒绝,则此创作者要发布的内容需要满足审核条件,即这条新创建的内容需要通过审核后才能发布。此时,我们在item_info表中为此内容设置online_version字段为0,表示此内容无线上发布版本,属于初次创建(这是理所当然的,因为新创建的内容尚未对外发布),同时设置latest_version字段为1,作为此次内容创建的version(版本号 ), 而将status(内容的状态)字段设置为“待审核”,其他字段留空。然后,将内容元信息暂存到item_record表中,填充全部字段,并设置latest_status字段为“待审核”。
如果此内容未命中审核时机策略,则意味着此创作者新创建的内容可被直接发布,于是直接设置online version和latest_version字段分别为1,同时将status字段设置为“正常展示”,将内容正式对外发布。
关于item_id,这里强烈推荐使用基于时间戳的分布式唯一ID生成器来生成,这样会使 item_id天然包含内容的发布时间,可以让我们很方便地识别一条内容是新内容还是旧内容,为对与内容相关的各种数据做冷热分离和数据路由提供了较大的自动化便利。
例如,我们约定发布时间为2022年1月1日至今的内容相关数据为热数据,其他时间发布的内容相关数据为冷数据,将热数据存储到性能较高的存储引擎中,将冷数据存储到资源相对廉价且容量大的存储引擎中。当请求一条内容的相关数据时,我们先读取此内容唯一标识item_id中的时间戳字段来判断是热数据还是冷数据,进而将请求路由到合适的存储引擎中来获取数据(在内容相关章节中会反复提及)。
在内容元信息创建完成后再次检查内容表现形式:如果内容包含短文本,则将短文本内容存储到分布式KV存储系统中,将{item_id}_{version}作为数据Key,将短文本内容作为数据Value。
至此,整个内容创建流程的设计就完成了。
现在我们通过图文形式重新描述这个流程。用户在客户端创建内容并上传内容的流程如下所述,如图7-3所示。
- 如果新创建的内容包含图片,则先将图片上传到后端的分布式对象存储系统中,此系统返回一个URI列表image_uris。如果新创建的内容包含长文本,则先将长文本以文件形式上传到后端的分布式对象存储系统中,此系统返回此文件的URI text uri。
- 如果新创建的内容包含视频,则先将视频上传到由专门的视频团队开发的视频服务中,视频服务返回一个视频ID video_id。
- 客户端携带创作者ID、内容文本、image_uris(图片URI列表)、text_uri (长文本URI)、video_id(视频ID)信息请求内容发布系统。
- 为新创建的内容生成一个基于时间戳的唯一ID,作为此内容的唯一标识。
- 将内容元信息存储到 item_info 表中,填充item_id、creator_id、visibility、create_time、update_time字段。如果创作者本身的条件需要被审核,则设置online_version字段为0,表示暂未创建成功,并将latest_version字段设置为1,作为此次内容创建的version;将status字段设置为“待审核”。而如果无须审核创作者本身的条件,则将online_version和latest_version字段分别设置为1,表示内容已发布。
- 如果内容包含短文本,则将短文本内容存储到分布式KV存储系统中,并设置存储项的Key为{item_id}_{version},Value为短文本内容。
- 将内容元信息再存储到item_record表中,填充全部字段。如果内容需要送审,则将latest_status字段设置为“待审核”,否则设置为“审核通过”。
- 如果内容需要送审,则通过异步消息队列方式将item_id、version异步发送到由专门的审核团队开发的审核中心服务中,由审核中心对新创建的内容进行审核。
7.4.2 内容的修改设计
内容修改与内容创建的流程大同小异,只不过在修改内容时会考虑是否要将此内容送审。
如果此次修改的内容之前已经达到送审的播放量、互动量的条件阈值,则此次内容修改需要通过审核,否则可以直接发布内容。
如果内容需要通过审核,则流程如下。
- 如果此次修改的内容有新增的图片,则先将图片上传到后端的分布式对象存储系统中,再将此系统返回的URI列表追加到此次提交的image_uris中。
- 如果此次修改的内容包含长文本,则先将长文本以文件形式上传到后端的分布式对象存储系统中,此系统返回此文件的URI:text_uri。
- 如果此次的内容修改是替换了新视频,则将新视频上传到视频服务中,视频服务返回一个视频ID:video_id。
- 客户端携带item_id、内容文本、image_uris、video_id、text_uri信息请求内容发布系统。
- 根据item_id查询item_info表中的记录,并将所找到的数据行的latest_version字段值加1,作为此次变更的version。
- 如果有内容短文本变更,则将内容短文本存储到分布式KV存储系统中,Key={item_id}_{version}。
- 将内容元信息再存储到item_record表中,填充全部字段,并将item_record表的latest_status字段设置为“待审核”。
- 将item_id、version异步发送给审核中心服务,由审核中心对此次修改的内容进行审核。
- 对于需要送审的内容,其修改流程的重点是不直接将修改后的内容更新到item_info表中,而是先将修改后的内容暂存到item_record表中。这是因为可能需要对此次修改的内容进行审核,来确认是否将此内容发布到线上。
如果内容不需要通过审核(创作者不满足审核条件),则流程如下(不涉及内容审核)。
- 如果此次修改的内容有新增的图片,则先将图片上传到后端的分布式对象存储系统中,再把此系统返回的URI列表追加到此次提交的image_uris中。
- 如果此次的内容修改是替换了新视频,则将新视频上传到视频服务中,视频服务 返回一个视频ID:video_id。
- 客户端携带item_id、内容文本、image_uris、video_id信息请求内容发布系统。
- 根据item_id查询item_info表中的记录,并将所找到的记录项的latest_version字段值加1,作为此次变更的version。
- 如果此内容主体包含短文本,则将内容短文本存储到分布式KV存储系统中,Key={item_id}_{version}。
- 将内容元信息再存储到item_record表中,填充全部字段,并将item_record表的latest_status字段设置为“已上线”。
如果创作者没有改动内容本身,仅仅修改了内容属性(比如调整内容的可见性),则直接更新item_info表即可。
7.4.3 内容审核结果处理与版本控制设计
回顾7.3节的内容,内容审核一般借助人工智能自动审核和人工审核完成,我们将内容审核视为黑盒,只需要知道:内容审核不一定能实时得出结果,审核结果只能通过异步通知的方式告知内容发布系统。7.3.4节介绍过,在有了审核结果后,审核中心会将审核结果发送到event_audit_result消息队列,消息内容是item_id、version、audit_result和reason(如果审核结果是“拒绝通过”)。下面介绍内容发布系统收到消息后的技术细节。
内容发布系统在收到event_audit_result消息队列中的审核结果后,需要根据审核结果决定是否发布内容。
- 如果审核结果是“审核通过”,则将item_record表中的此item_id、此版本version的暂存数据覆盖到item_info表中,表示发布内容。
- 如果审核结果是“审核拒绝”,则在item_record表中的此item_id、此版本version 对应的数据行中,设置latest_status字段为“审核拒绝”,并将拒绝原因reason设置到latest_reason字段中。
不过,在上述审核结果是“审核通过”的处理逻辑中,还有一个重要的问题:既然在有了审核结果后,审核中心会将消息发送到event_audit_result消息队列中,那么我们需要重点考虑消息的顺序问题。
假设一个用户在短时间内进行了三次内容变更 ,这三次变更内容的版本号分别为100、101、102,依次将其投递到审核中心(假设审核中心对这三个版本的变更内容的审核结果都是“审核通过”)。在正常逻辑上,内容创作者当然希望最终发布的内容是102版本。但是,审核中心并不会保证这三个版本的变更内容的审核响应速度与回调顺序。比如审核中心对100版本的变更内容耗时10min才得出审核结果,对101版本的变更内容耗时5min得出审核结果,而对102版本的变更内容仅耗时10s便得出审核结果,即在审核速度上,102版本>101版本>100版本,那么内容发布系统将会先收到102版本的审核回调,再收到101版本的审核回调,最后才收到100版本的审核回调。如果内容发布系统每收到一条内容审核通过消息,就直接更新item_info表,那么最终item_info表的数据是100版本的变更内容,与内容创作者的预期相悖。
那么,怎么才能如内容创作者所预期的那样,最终使得102版本的变更内容生效呢?由于三次变更内容的版本号是单调递增的,所以解决方法很简单。
内容发布系统在收到内容审核通过的消息后,先检查当前item_info表中的online_version(线上内容的版本号)字段:
- 如果审核通过的version(内容版本号)小于online_version,则说明是更早的内容变更版本,变更生效会导致内容回退,于是忽略此次回调;
- 否则,说明是新的内容变更,于是更新item_info表。
这样一来,无论变更内容的哪个版本先回调审核结果,最终线上生效的内容版本一定是版本号最大的变更内容。
内容审核结果的处理流程设计如下所述,如图7-4所示。
- 审核中心完成审核,将 item_id、version、audit_result、reason信息打包成一条消息发送到event_audit_result消息队列中。
- 内容发布系统收到event_audit_result消息队列中的消息,根据所收到消息的item_id和version,先查询item_record表中的记录,将latest_status字段设置为“audit_result”,将 latest_reason字段设置为“reason”,再进一步检查audit_result的值 :
- 如果audit_result的值是“拒绝通过”,则不再进行下一步操作;
- 如果audit_result的值是“审核通过”,则继续进行下一步操作。
- 如果audit_result的值是“审核通过”,则查询item_info表中线上内容的版本号:
- 如果online_version=version,则说明此次审核的内容是线上内容(可能是内容的播放量、互动量达到审核阈值,或者内容被用户投诉),将审核结果写入item_info表中的status 字段;
- 如果online_version<version,则说明此次审核结果对应的内容版本比线上的新,是新变更的内容,需要执行第4步;
- 使用item_record表中的记录替换item_info表中的数据行:item_info表中行数据的online_version、online_image_uri、online_text_uri、online_video_id字段的值被依次替换为item_record表中行数据的latest_version、latest_image_uris、latest_text_uri、latest_video_id字段的值,完成了对内容的线上发布。
这就是在7.3节一笔带过的“内容审核结果处理”的详细设计流程。
7.4.4 内容的删除与下架设计
用户可以删除自己不想再展示的内容,产品运营人员也可以在内容运营后台(对公司内相关员工开放的用户内容管理系统)将高风险或不合规的用户内容下架,这两种操作最终的结果都是内容不再被展示。
当内容被删除、下架时,我们应该采用软删除策略,即只标记item_info表的数据行中的status字段为“被删除”或“被下架”,而不是直接删除数据行。这样做能让我们清晰地知道内容消失的原因是什么,有助于对“内容不可见”类型的问题反馈进行排查。
总结
当创作者在产品客户端新创建了一条内容并准备将其提交到内容发布系统的服务端时,我们应该怎么处理这个请求?
- 首先,客户端需要进行内容数据类型的识别和归类。如果新创建的内容包含长文本图片,则需要先将它们以文件形式上传到分布式对象存储系统中。如果分布式对象存储系统成功存储了这些文件,则会返回长文本URI和图片URI;如果新创建的内容包含视频,则由于涉及必要的视频编解码,所以需要先将本地视频文件上传到由专门的视频团队开发的视频服务中(这个服务会先对视频进行转码,然后把结果存储到分布式对象存储系统中),并由视频服务返回一个唯一的视频ID代表这个视频,我们可以根据这个视频ID从视频服务中获取视频。
- 然后,在将这些特殊文件存储到服务端后,客户端会收到服务端的响应,接收到长文本URI、图片URI和视频ID。
- 最后,客户端携带创作者信息、内容可见性设置、内容短文本及服务端返回的长文本URI、图片URI和视频ID再次请求服务端。此时,我们在内容发布系统中为此内容创建元信息:通过分布式唯一ID生成器生成一个全局唯一的item_id来标识这条内容,并填充item_info 表的item_id、creator_id(创作者ID)、visibility(内容可见性)、create_time(内容创建时间)和 update_time(内容变更时间)字段。
用户在客户端创建内容并上传内容的流程?
- 如果新创建的内容包含图片,则先将图片上传到后端的分布式对象存储系统中,此系统返回一个URI列表image_uris。如果新创建的内容包含长文本,则先将长文本以文件形式上传到后端的分布式对象存储系统中,此系统返回此文件的URI text uri。
- 如果新创建的内容包含视频,则先将视频上传到由专门的视频团队开发的视频服务中,视频服务返回一个视频ID video_id。
- 客户端携带创作者ID、内容文本、image_uris(图片URI列表)、text_uri (长文本URI)、video_id(视频ID)信息请求内容发布系统。
- 为新创建的内容生成一个基于时间戳的唯一ID,作为此内容的唯一标识。
- 将内容元信息存储到 item_info 表中,填充item_id、creator_id、visibility、create_time、update_time字段。如果创作者本身的条件需要被审核,则设置online_version字段为0,表示暂未创建成功,并将latest_version字段设置为1,作为此次内容创建的version;将status字段设置为“待审核”。而如果无须审核创作者本身的条件,则将online_version和latest_version字段分别设置为1,表示内容已发布。
- 如果内容包含短文本,则将短文本内容存储到分布式KV存储系统中,并设置存储项的Key为{item_id}_{version},Value为短文本内容。
- 将内容元信息再存储到item_record表中,填充全部字段。如果内容需要送审,则将latest_status字段设置为“待审核”,否则设置为“审核通过”。
- 如果内容需要送审,则通过异步消息队列方式将item_id、version异步发送到由专门的审核团队开发的审核中心服务中,由审核中心对新创建的内容进行审核。
如果内容需要通过审核,则流程如下?
- 如果此次修改的内容有新增的图片,则先将图片上传到后端的分布式对象存储系统中,再将此系统返回的URI列表追加到此次提交的image_uris中。
- 如果此次修改的内容包含长文本,则先将长文本以文件形式上传到后端的分布式对象存储系统中,此系统返回此文件的URI:text_uri。
- 如果此次的内容修改是替换了新视频,则将新视频上传到视频服务中,视频服务返回一个视频ID:video_id。
- 客户端携带item_id、内容文本、image_uris、video_id、text_uri信息请求内容发布系统。
- 根据item_id查询item_info表中的记录,并将所找到的数据行的latest_version字段值加1,作为此次变更的version。
- 如果有内容短文本变更,则将内容短文本存储到分布式KV存储系统中,Key={item_id}_{version}。
- 将内容元信息再存储到item_record表中,填充全部字段,并将item_record表的latest_status字段设置为“待审核”。
- 将item_id、version异步发送给审核中心服务,由审核中心对此次修改的内容进行审核。
- 对于需要送审的内容,其修改流程的重点是不直接将修改后的内容更新到item_info表中,而是先将修改后的内容暂存到item_record表中。这是因为可能需要对此次修改的内容进行审核,来确认是否将此内容发布到线上。
如果内容不需要通过审核(创作者不满足审核条件),则流程如下(不涉及内容审核)?
- 如果此次修改的内容有新增的图片,则先将图片上传到后端的分布式对象存储系统中,再把此系统返回的URI列表追加到此次提交的image_uris中。
- 如果此次的内容修改是替换了新视频,则将新视频上传到视频服务中,视频服务 返回一个视频ID:video_id。
- 客户端携带item_id、内容文本、image_uris、video_id信息请求内容发布系统。
- 根据item_id查询item_info表中的记录,并将所找到的记录项的latest_version字段值加1,作为此次变更的version。
- 如果此内容主体包含短文本,则将内容短文本存储到分布式KV存储系统中,Key={item_id}_{version}。
- 将内容元信息再存储到item_record表中,填充全部字段,并将item_record表的latest_status字段设置为“已上线”。
如果创作者没有改动内容本身,仅仅修改了内容属性(比如调整内容的可见性),则直接更新item_info表即可。
内容审核结果的处理流程设计?
- 审核中心完成审核,将 item_id、version、audit_result、reason信息打包成一条消息发送到event_audit_result消息队列中。
- 内容发布系统收到event_audit_result消息队列中的消息,根据所收到消息的item_id和version,先查询item_record表中的记录,将latest_status字段设置为“audit_result”,将 latest_reason字段设置为“reason”,再进一步检查audit_result的值 :
- 如果audit_result的值是“拒绝通过”,则不再进行下一步操作;
- 如果audit_result的值是“审核通过”,则继续进行下一步操作。
- 如果audit_result的值是“审核通过”,则查询item_info表中线上内容的版本号:
- 如果online_version=version,则说明此次审核的内容是线上内容(可能是内容的播放量、互动量达到审核阈值,或者内容被用户投诉),将审核结果写入item_info表中的status 字段;
- 如果online_version<version,则说明此次审核结果对应的内容版本比线上的新,是新变更的内容,需要执行第4步;
- 使用item_record表中的记录替换item_info表中的数据行:item_info表中行数据的online_version、online_image_uri、online_text_uri、online_video_id字段的值被依次替换为item_record表中行数据的latest_version、latest_image_uris、latest_text_uri、latest_video_id字段的值,完成了对内容的线上发布。