作者介绍 @知乎:邹志全 专注营销系统提效 自动化营销精细运营的长期实践者 做有效编码 “数据人创作者联盟”成员。 用户标签体系 用户标签通常分为用户实时业务状态标签、用户画像特征标签两种。 实时业务特征通常来源于实时业务系统的接口或者DB,而用户画像特征标签这个通常是算法平台提供,用户标签所要承受的qps数是除唯一单号服务外最大的,所以通常性能要求高(承载qps量大、耗时短),但可用性要求倒是没那么高(一个合理的系统,在不知道用户信息的情况下也应该能正常作出兜底反应的) 通常来说,我认为一个合理的在线标签系统是这样的: 单独具有流量控制功能,保证大部分流量可用,降级掉一部分请求,对常用的标签进行缓存控制<标签key,用户id,统一有效时间>,根据需要获取可接受时间范围内用户标签。 未命中缓存的标签,交由标签任务管理器进行处理,决定单个标签处理最大时长、标签并行&串行处理机制及处理顺序、处理任务调度等,底层维护并发模型(线程数、任务存放机制等) 再下一层,维护对外部接口、业务数据或接口、用户画像数据的处理单元。 短链服务 上文在触达单元中就提到了短链服务,首先业务常见、技术特点鲜明,所以单独拿出来说了。短链服务的应用场景非常多,除了短信中的链接,平日里的链接分享、网页分享、二维码分享其实斗志这种方式,只是表现形式不同而已。短链接实现思路很简单: 找一个短链接试试看:http://3.cn/j/10nd-pE9 至于这里为什么用的是302而不是301,是因为临时重定向时能够统计到短链接点击次数,通常也会被用作效果分析。用301永久重定向也是可以的。 至于后面“10nd-pE9”这个码,通常被称为短码,生成方式有很多种,比如上面提到的唯一单号,还有就是摘要法(存在小概率重复的可能性,但能够保证链接够短)。如果是小型企业大可以利用现成的短链服务提供商,比如百度的:https://dwz.cn/ 基础活动单元 抽奖活动单元将常见的活动形式进行了一定程度上的抽象,做了通用化处理,以应对其高频的需求。这里拿几个经典的活动形式进行阐述。活动单元的建立,可以根据具体的业务场景下的各种运营的需求来进行拆分抽象。 谈谈抽奖 拿抽奖来说,摇一摇是抽奖,九宫格转盘是抽奖,n选一砸金蛋也是抽奖,大家点的火热朝天的红包雨其实也是抽奖,这类抽奖活动对用户活跃度非常有帮助,用户分享意愿也很强,基本是大型活动每次必选的组成部分。所以就完全可以对其进行抽奖建立一个通用的抽奖模型。整体看下来一个抽奖系统是这样的: 其中的核心组件有: 概率模型 用户控制用户中奖的概率,实现方式很简单: 1、确定可抽奖总区间,确定奖品区间段,一次性进行抽奖。 2、Alias Method 可以直接看这一篇实现:http://www.keithschwarz.com/darts-dice-coins/ 大致意思:把N种可能性拼装成一个方形(整体),分成N列,每列高度为1且最多两种可能性,可能性抽象为某种颜色,即每列最多有两种颜色,且第n列中必有第n种可能性,这里将第n种可能性称为原色。 想象抛出一个硬币,会落在其中一列,并且是落在列上的一种颜色。这样就得到两个数组:一个记录落在原色的概率是多少,记为Prob数组,另一个记录列上非原色的颜色名称,记为Alias数组,若该列只有原色则记为null。 抽奖机会控制 提供用户可抽奖机会的控制,是一种价值的载体。抽奖系统对外暴露次数增加接口,内部抽奖行为消耗抽奖次数。 奖池控制 每个用户群面向自己的奖品集合,高价值的用户或者潜在用户面向价值较高的奖品,风险用户或者下沉用户面向低价值的优惠券等,就是这么黑。这里通常依赖于表达式引擎,根据标签计算用户所选奖池。 中奖限制 曾经的我也以为奖可以随便中,除了面向奖品集合之外,通常对用户会额外加n多限制条件。 比如说,a奖品最多中2次,b奖品最价值不能超过2元,命中iphone大奖后其他不能再中大奖并且其他奖品概率下降。 库存控制 所有的奖品都是有成本预算的,不能无限制发放,这就要求对奖品进行库存控制。这里有一个设计的思路,分别设置库存供应量、库存消耗量,剩余库存=库存供应量-库存消耗量,这样相对于拿一个数值表示库存进行增减操作要灵活的多并且安全很多,尤其适合在库存增加时。 另外,库存的消耗操作很显然是一个存在竞态条件的复合操作,我们需要保证其原子性,可以利用上锁等措施串行化,也可以利用现有工具的原子能力(比如reids 操作的原子性:incrby、lua等) 裂变营销 这里还有一个值得提的是列表营销,当下正火的营销方式,最经典的莫过于“帮我砍一刀”。分开来看,营销上面说过了,裂变概括来说,按生物学来说是细胞核的裂变,由一个裂变成2个,2个裂变成4个。 换作人来说,就是当前用户是否能够帮忙获客。对于裂变营销而言,通常包含三个环节,设计裂变流程,裂变流程变为转化漏斗,漏斗分析。 裂变营销重在逻辑,性能等要求一般不会很高。对于系统设计而言有几块格外的重要: 1、底层邀请关系组件 裂变营销往往是从人出发,以人结束,造出一颗颗庞大的树,所以我们需要维护整个树的结构,不仅仅是为了存储活动的邀请记录供激励使用,对后期判断“散点”也是尤为重要的。 2、标签组件 活动的重心在于拉人,什么样的人能拉人,是相当重要的,要建立与裂变营销关联性很强的人群画像标签十分重要。这块了解的不多,暂时就这些~ 数据的一致性处理 数据一致性一直是各种系统很头痛的点,尤其是分布式系统越来越昌盛的今天。数据一致性也存在cap、base这样的著名的理论,实际上平衡一致性与性能、可用性等特性是需要根据产品特点来做的,像跟钱相关的一致性要求会非常的高(不能出错),积分数量这种虚拟权益类其次,签到记录等用户就不太关心了。 营销场景下的一致性要求 营销场景的数据一致性要求其实是相对宽松的,只需要在较短的时间内保证最终一致就可以了。 拿抽奖活动举例,一次抽奖行为的发生,涉及到次数减扣、库存减扣、抽奖记录更新、奖品发放等一系列的操作,很有可能会发生部分失败,按照常理来说像奖品发放失败这样的情况,短时间未到账用户大概率也是无感知的,通常需要绕道卡券包等,所以这种情况我们只需要一定时间段内给用户补上即可,需要保证的主要是和成本密切相关的次数、库存等。 当然啦,一致性要求虽然没有那么高,但是还是要尽可能照顾到的,没有数据一致性的保证,性能、可能性再高的系统可能都是一堆垃圾。 常见的一致性实现方案 先来看一下什么是数据一致性:数据的变更,与现实世界变更的预期结果保持一致。后来在这个基础上延伸出: 各种一致性 强一致性(也称线性一致性):任何一次读都能读到某个数据的最近一次写的数据,系统中的所有进程,看到的操作顺序,都和全局时钟下的顺序一致。 弱一致性:用户读到某一操作对系统特定数据的更新需要一段时间,我们称这段时间为“不一致性窗口”。最终一致性:是弱一致性的一种特例,保证用户最终能够读取到某操作对系统特定数据的更新。 顺序一致性:任何一次读都能读到某个数据的最近一次写的数据,系统的所有进程的顺序一致,而且是合理的。(相对于强一致性少了系统时钟) 事务的诞生,很大程度上就是为了保证数据的一致性。 基础理论 cap:指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)只能满足两其中两点。 base:BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩 写。 BASE理论是对CAP中AP的一个扩展,保证可用性和分区容错的情况下,允许存在软状态,但会保证最终一致性。 两阶段提交 这部分理论知识蛮陈旧的就不展开说了,大体能懂就好:二阶段提交的算法思路可以概括为: 参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。 两阶段的缺点:1、同步阻塞问题。2、协调者的单点故障问题。3、第二阶段执行中,协调者与参与者共同挂掉的场景导致不一致。 三阶段提交 三阶段提交协议在协调者和参与者中都引入超时机制,并且把两阶段提交协议的第一个阶段分成了两步,引入了中间状态: 询问,然后再锁资源,最后真正提交。 解决了“同步阻塞”、”单点故障“等小缺点,及二阶段无法解决的“协调者与参与者共同挂掉的场景导致不一致”这个很重要的问题。 说实话不管是两阶段或者三阶段,都无法彻底解决一致性问题。 刚性&柔性事务 刚性事务:具备我们熟知的的ACID的特性的事务,通常的实现有WAL(white ahead log)(这是目前市面上几乎所有数据库的实现方式),还有一种是影子分页。 柔性事务:基于base理论实现的追求最终一致性的事务模型,通常实现方式包括TCC补偿性事务、异步确保型、最大努力型。tcc分布式事务是一种二阶段的变种,将操作分为尝试、提交、撤销,是一种实时链路上的的操作行为。 大致模型是这样的:事务发起者发起一个事务,参与者进行事务的提交操作,如果其中几个参与者本地事务失败,会告知失败,其他已提交的参与者事务进行补偿操作进行回滚。 异步确保型事务则为将同步阻塞的事务操作变为一步操作,避免对数据库事务的争用,对操作进行汇总处理,通常对于热点资源的操作采用这种方式。 最大努力型事务,依赖于补单消息的补偿机制或者重试机制,对事务进行最大程度的推进,以此保证最终一致性。 营销场景下的数据一致性设计 首先看完上述的上面各种的一致性定义和分布式事务实现可以发现,数据的一致性实现是比较困难的,也是业界一直在寻求最优解的问题之一,但就目前而言,实时链路上的各种分布式事务能保证一定程度上的数据一致性,而且通常来说只是局部某个环节(不可能把所有事情都扔进事务里面),并且还会有一定的瑕疵。 对于整个业务逻辑推进中数据一致性的根本保证,还是最原始的:“建立业务流转的状态机,依赖于唯一单号,异步对账补单,达到最终一致性” 对于营销场景下,性能要求较高,但一致性要求没有那么强。建议的实现方式有两种: 1、核心操作采用TCC事务模型实现,保证核心链路上核心数据的一致性,对于附属操作可通过异步对账补单保证最终的一致性。 2、实时链路不做分布式事务处理,完全依赖于对账补单实现。 每种方式都有自己的优缺点,第一种方式所需的对账补单量级较小,常见的掉单失败等在实时主链路上就给干掉了,对于数据不一致引发的问题的影响时长会减少,但是引入了TCC事务,增加了三方协调和更多的网络IO,数据操作逻辑的复杂度会直线上升,性能会有一定程度的下降,可能会产生新的风险和问题。 而第二种方案,主链路代码精炼,性能会很好,但对于数据不一致引发的问题的影响时长会较长,并且对账补单系统规模会变的庞大,要处理的任务也会变多。 既然各有优缺点,我们就需要根据不同营销场景来选择,像是营销组件完全是组件内操作本地事务或者不需要事务即可解决,对于常规活动依赖于活动单元组件这些建议使用第一种方案,直接建立较为完备的措施,一劳永逸。 而像是性能要求非常高并且逻辑相对简单的临时活动,第二种方案就足够了,释放出人力处理性能优化。像是非常大型的营销活动,就需要根据具体场景来衡量了,数据一致性可能产生的影响面,性能、可用性、一致性的折中。 这块内容没有标准答案,包括了解的各种业务场景都是这样的,数据一致性通常需要根据场景定制化开发,并不存在通用解决方案。而我们需要做的就是积累一致性处理经验和数据一致性保证的可选方案(除了TCC这些,业界存在很多解决方案,除了TCC这种还有事务型消息、本地消息表等,但是都逃不出上面的那一堆概念的基础理论知识)。
发表评论 取消回复