微信红包系统整体架构分析探讨

目录

一、微信红包系统架构前置背景分析

(一)功能分析

(二)业务特点分析

(三)技术难点分析

二、微信红包系统详细架构设计分析

(一)整体架构分析

微信统一接入层

业务逻辑层

数据存储和分析层

底层支持服务

(二)基本数据表设计

红包表(redpack)

红包记录表(redpack_record)

发红包的交互流程

抢红包的交互流程

数据库设计优化要点

(三)高并发解决方案分析

解决方案要素一:单元化Set架构

具体实现说明

单元化架构的优势

解决方案要素二:红包系统的数据库并发问题

逻辑 Server 层请求排队机制

单机请求排队机制

Redis 缓存层控制并发

解决方案要素三:双维度分库分表设计

冷热数据分离

双维度分库分表设计

(四)红包分配算法分析:揭秘如何让抢红包更刺激!

实时拆分:每次都随机分配

为什么要保证随机?

实际中的小秘密

看一下代码是怎么实现的

(五)高可用解决方案分析

三、系统扩展分析:平衡扩容问题

(一)搭建新 SET

(二)逻辑服务根据订单号分配到对应 SET

(三)请求路由与数据库故障自愈

四、总结

参考文章


干货分享,感谢您的阅读!

在除夕夜的倒计时中,数亿人同时打开微信,期待收到或发出一个红包。这看似简单的操作背后,却是对技术极限的挑战(以2017年除夕为例,微信红包在短时间内达到了76万QPS的峰值,并在一天内处理了142亿个红包交易)。面对百亿级别的数据量和瞬时百万QPS的并发压力,微信红包系统如何确保稳定运行、资金安全、用户体验流畅?这一切依赖于背后复杂而精密的架构设计。本文我们展开探讨微信红包系统的设计之道和高并发场景下的技术奥秘,如果有误请留言指正,感谢各位。

一、微信红包系统架构前置背景分析

在设计微信红包系统之前,我们需要充分理解其背后的业务需求和技术挑战。微信红包不仅是一种社交工具,更涉及支付安全、资金流转和高并发场景下的用户体验优化。为了确保在极短时间内应对大规模流量冲击,系统架构必须充分考虑功能、业务特点以及潜在的技术难点。接下来,我们将从功能、业务特点和技术难点三个方面深入分析微信红包系统的设计前置背景。

(一)功能分析

微信红包系统作为一个支付和社交结合的复杂系统,主要功能涵盖了从发红包到抢红包再到拆红包的完整流程。每个功能环节都与微信支付系统紧密交互,确保资金流转的安全性和用户体验的流畅性。

  1. 包红包系统首先为每个红包生成一个唯一的订单号,并记录红包的相关信息(如红包金额、数量、发送对象等)。这些信息将被持久化存储,以备后续操作使用。

  2. 发红包当用户发起红包并通过微信支付完成付款后,系统会接收到支付成功的通知,并更新红包订单状态为“已支付”。接着,系统会将红包消息推送至目标微信群,红包的支付流水和记录也会同步更新到用户的钱包中,便于用户查看发红包记录。

  3. 抢红包群内用户点击红包后,系统将进行一系列验证,包括检查红包是否已抢完、是否过期、用户是否已抢过等。只有通过这些验证,用户才有资格抢到红包。

  4. 拆红包拆红包是整个流程中最复杂的操作。系统首先查询红包订单信息,判断用户是否有资格拆红包。然后,系统根据逻辑分配用户可抢到的金额,并记录抢红包流水。接着,系统将扣减红包剩余金额并更新订单状态,最后调用微信支付将用户抢到的金额转入其零钱账户,成功后更新订单为“已转账成功”。

通过上述功能模块的协同工作,微信红包系统实现了从用户发起到红包到账的完整闭环,保障了用户体验和资金安全。

(二)业务特点分析

微信红包的业务形态,特别是群红包,与普通商品的"秒杀"活动有许多相似之处:

  • 包红包 = 秒杀商品管理系统为红包分配唯一订单号,类似于为秒杀商品进行库存管理,记录红包的金额、数量等关键信息。

  • 发红包 = 商品上架用户支付后,红包相当于商品上架,系统将红包推送到微信群,供用户抢夺。

  • 抢红包 = 查询库存群用户点击抢红包时,类似于秒杀时查询商品库存,系统需要验证红包的剩余金额、有效性及用户资格。

  • 拆红包 = 用户秒杀动作拆红包相当于秒杀成功,系统计算并分配红包金额,更新库存并将金额转入用户零钱,确保交易的准确性与及时性。

这种类比有助于理解微信红包的业务流程,但微信红包涉及资金流转,安全性和准确性要求更高,处理难度也更大。

(三)技术难点分析

微信红包系统在设计和实现过程中面临多个技术难点,尤其是在高并发、资金安全、用户体验和数据一致性方面。具体来说可能有如下的一些技术难点分析:

  1. 高并发难点每逢春节或节假日,微信红包会遭遇极高的并发量,瞬时请求数以百万计。如何在这种情况下有效处理请求,确保系统稳定且响应迅速,是设计的关键挑战。系统需要使用分布式架构、缓存、异步处理等技术手段,分摊流量,避免出现性能瓶颈。

  2. 资金安全难点红包涉及资金交易,必须保证资金的安全和准确性。红包不能出现“超卖”或“少卖”的问题,系统必须精准控制资金流动,确保发出的金额与抢到的金额相符,并处理好未抢完金额的退还工作。任何资金错误都可能带来法律和用户信任问题,因此,系统在设计上必须具备强大的安全性和容错机制。

  3. 用户体验难点在高并发场景下,用户体验是另一个重要难点。微信红包系统需要在极短时间内完成发、抢、拆红包的流程,确保响应迅速、操作流畅。为了优化用户体验,系统需重点关注摇红包流畅度、抢红包速度、拆红包的乐趣,并且能够稳妥分享红包链接。如何在高流量环境中兼顾速度和公平性,是系统设计的关键。

  4. 数据一致性难点红包业务需要保持数据一致性,包括红包库存、用户账户余额等。在高并发场景下,事务处理的复杂性增加,系统必须确保不会出现“脏数据”或不一致的状态,尤其是在涉及资金流转时。为此,系统可能需要采用分布式事务管理、数据锁定以及事务隔离技术,确保在高并发条件下保持数据的一致性和准确性。

  5. 系统扩展性难点随着用户量和业务量的持续增长,系统的扩展性变得尤为重要。红包系统需要具备良好的扩展性,以便在用户规模扩大或业务需求增加时,能够轻松扩展容量和增加功能。通过分布式架构设计、读写分离、水平与垂直拆分等手段,系统可以灵活扩展,支持更多用户和更复杂的业务场景。

为解决这些技术难点,直观上我们需要具体可涉及以下内容的基本考虑。

二、微信红包系统详细架构设计分析

(一)整体架构分析

从图中可以看到,微信红包系统的整体架构可以分为以下几个模块:

微信统一接入层

这是所有请求进入系统的第一层,也是系统的入口。微信红包系统通过接入层处理来自用户的请求,比如发红包、抢红包、拆红包和查红包。接入层的设计要考虑高并发,确保系统能够高效、稳定地处理大量的请求。

业务逻辑层

该层主要负责微信红包的核心功能,包括发红包、抢红包、拆红包和查红包。每个功能模块都有专门的业务逻辑处理。

此外,业务逻辑层还包括异步逻辑处理和异常数据接口,用于处理系统的异步任务和数据异常情况,确保系统在出现问题时能够快速响应和恢复。

  • 发红包:负责生成红包订单,分配红包金额,并将红包发给用户。
  • 抢红包:用户点击红包后,系统要验证红包状态(是否被抢完、是否过期等),并确保抢红包过程的高效和公平。
  • 拆红包:系统实时计算用户能够拆到的红包金额,并进行金额分发,确保资金安全。
  • 查红包:提供用户查询红包状态、领取情况等功能。

数据存储和分析层

该层主要负责历史数据、订单数据、用户数据等重要信息的存储和处理。

  • KV缓存:用于存储一些高频访问的数据,减轻数据库的压力,加快系统响应速度。
  • 数据同步:确保不同模块的数据一致性和实时性,特别是在南北独立体系下,数据同步至关重要。
  • 对账审计:确保资金交易的准确性,避免超卖、少卖等资金安全问题。
  • 数据分析:用于分析用户行为、红包使用情况等,为后续的业务优化和扩展提供数据支持。

底层支持服务

  • 微信基础服务:提供基础功能支持,包括身份验证、消息推送、群组管理等,确保系统能够与微信生态无缝对接。
  • 微信支付:这是微信红包系统与支付系统的核心交互部分,负责处理用户的支付请求、红包金额分发等资金流转过程。

通过接入层和业务逻辑层的独立划分,结合KV缓存和异步处理的设计处理微信红包系统的海量并发请求。通过订单数据、用户数据的精细管理,结合对账审计,保证了资金交易的安全性,避免资金流动中超卖或少卖的风险。而数据同步模块和对账审计机制的设计,确保了数据的一致性,而南北独立的订单体系也有助于系统的负载均衡和扩展。

具体一些重点的设计可见如下基本部分的分析。

(二)基本数据表设计

微信红包系统的数据库设计主要包括两张核心表:红包表(redpack)红包记录表(redpack_record)。它们分别记录红包的基本信息以及用户抢红包的详细记录。

注意以下分析是基于数据表级别的简单处理分析,高并发和高可用的设计见后续的分析部分。

红包表(redpack)

红包表用来记录每个红包的基本信息包括红包的总金额、剩余金额、总个数及剩余个数等信息,以便跟踪红包的整体状态。该表的主要字段及其含义如下:

字段名描述
id主键,唯一标识红包的ID。
user_id发送红包用户的ID。
total_amount红包的总金额。
surplus_amount红包的剩余金额。
total红包的总个数。
surplus_total剩余未被抢的红包个数。

业务逻辑:当用户发起红包时,系统会在此表中创建一条新的红包记录。随着红包的拆取,系统会更新surplus_amountsurplus_total字段,直到红包被抢完或超时。

红包记录表(redpack_record)

红包记录表用来存储每个用户抢到的红包金额,确保每次抢红包的操作记录在案,方便后续的对账和统计。该表的字段如下:

字段名描述
id主键,记录ID。
redpack_id关联的红包ID。
user_id抢到红包的用户ID。
amount用户抢到的具体金额。

业务逻辑:每当用户成功拆开红包后,系统会在redpack_record表中创建一条记录,记录该用户抢到的金额,同时对红包表的剩余金额和剩余个数进行更新。

发红包的交互流程

发红包的主要步骤可以分为以下几部分:

  1. 设置红包参数:用户设置红包的总金额和个数,系统会在红包表中插入一条新记录,记录相关红包信息。
  2. 付款成功更新:用户完成微信支付后,系统收到支付成功通知,更新红包表中的红包状态为“已支付”,并调用微信接口将红包信息推送至指定的微信群。
  3. Redis 缓存:为了保证高并发情况下的实时性,系统在Redis中记录红包的ID和剩余红包个数,通过缓存加快抢红包的响应速度。
  4. 群消息推送:系统将抢红包消息推送给微信群成员,等待用户点击抢红包。

抢红包的交互流程

抢红包和拆红包在微信红包系统中是两个分离的服务,具体流程如下:

  1. 抢红包:用户点击红包时,系统首先通过Redis中的记录来判断红包是否还有剩余。如果surplus_total已为0,则红包被抢完。抢红包过程由Redis的原子递减操作完成,以保证多用户并发操作时,红包个数能准确更新,避免超卖或少卖的情况。

  2. 拆红包:拆红包时,系统会使用二倍均值法(即在0.01到剩余金额平均值的2倍之间随机分配)计算用户能够获得的红包金额。每次拆红包都会在红包记录表redpack_record中生成一条新记录,并通过数据库事务确保红包总金额和已领取金额的正确性。

  3. 异步转账:为了提升系统性能,用户抢到红包后的金额不会立即转账到零钱账户。实际的转账操作是异步执行的,因此在高峰期间(如春节),用户可能会发现抢到红包后,余额并未立刻更新。

数据库设计优化要点

  • Redis 缓存加速:通过在Redis中缓存红包剩余个数和金额,提升了抢红包操作的响应速度,减轻了数据库的压力。
  • 事务处理:为保证红包金额分配的准确性,抢红包和拆红包的操作需要通过事务进行处理,避免出现并发数据不一致的情况。
  • 异步处理:为了减轻主数据库和支付系统的压力,最终的转账操作被设计为异步执行,保证高并发情况下的系统稳定性。

微信红包系统的数据库设计通过红包表与红包记录表的搭配,合理地记录了每个红包的状态和每个用户的抢红包情况。结合Redis缓存、事务处理和异步转账等技术手段,系统能够在高并发场景下保证性能和数据一致性,同时提升了用户的抢红包体验。

(三)高并发解决方案分析

微信红包系统的高并发问题是其架构设计中的一个关键挑战,尤其是在重大节日如春节期间,系统要处理亿万级别的并发请求。

解决方案要素一:单元化Set架构

为了有效解决这个问题,微信红包系统采用了单元化架构(Set化架构),这是一种"分而治之"的架构设计方法。接下来我们将详细讲解这一方案。

单元化架构是指将系统按照某个维度进行划分,分成多个独立的、功能完备的单元(Set),每个单元都能够独立完成业务操作。每个单元内包含了完成业务所需的全部服务、数据库和资源,且这些单元可以独立部署和运作。这种架构设计类似于将一座大城市(整体系统)分成多个独立的小区(单元),每个小区都自成体系,拥有自己的设施和服务。

举个简单的例子:系统被划分为多个商场,每个商场都提供相同的服务,用户根据某种规则被分配到不同的商场购物,避免了拥堵。

在微信红包系统中,单元化架构的关键在于:所有的红包操作(发红包、抢红包、拆红包、查询红包)都基于唯一的红包ID关联,所有请求会固定路由到同一个单元中处理

具体实现说明

当用户发起一个红包时,系统会生成一个唯一的红包ID。接下来,围绕这个红包的所有操作(如发红包、抢红包、拆红包、查询详情)都会基于这个ID处理。为了避免海量请求集中到一个服务器或数据库,系统对红包ID进行了切分垂直化处理,将所有红包相关请求分散到不同的单元(Set)中。

具体流程如下:

  1. 红包ID的生成:每个红包都有唯一的红包ID作为标识,类似于一张购物凭证,用户的所有操作都需要基于这张凭证。

  2. 基于ID的垂直切分:系统根据红包ID,按一定规则(例如红包ID尾号取模)将请求路由到不同的单元。这样,红包ID尾号不同的请求将被分配到不同的服务器和数据库上处理,避免单点压力。每个单元包括逻辑服务器、数据库,这些服务器和数据库之间彼此独立,互不影响。

  3. 固定路由(Stick to Set):一旦红包ID被分配到某个单元,所有围绕该红包的后续操作都将在同一单元内完成。这意味着用户的发红包、抢红包、拆红包、查询红包等所有操作都在同一个链条server上进行,形成高度内聚,避免跨单元请求带来的延迟和复杂性。

  4. 互相解耦:每个单元都是独立的,彼此之间没有直接依赖关系。如果某个单元出现故障,只会影响该单元内的请求,其他单元不会受牵连。这提高了系统的可靠性和可扩展性。

单元化架构的优势
  • 高并发处理能力增强:通过对红包请求的分而治之,将海量的请求拆解成若干小的请求流,每个单元只需处理属于自己的部分业务,不同单元的请求互不干扰,有效降低了单点压力。
  • 系统的扩展性:系统可以根据业务量的增长,动态增加新的单元来承载更多的请求。由于每个单元彼此独立,系统的扩展非常灵活,只需增加更多的硬件资源和单元即可。
  • 提高容错性:单元化架构天然具有良好的容错性。因为各个单元是相互独立的,某个单元出现问题只会影响该单元内的业务,不会波及其他单元。因此,即使发生部分服务器故障,系统仍能继续正常服务。
  • 数据库性能优化:每个单元的数据库只处理该单元内的红包操作,避免了数据库被集中请求压垮的风险。这使得数据库的负载被均匀分摊,各单元的数据库能够在相对轻松的环境下高效运行。

高并发时,微信红包系统可能要面对数亿次的红包发放和拆红包请求。微信红包系统通过采用单元化架构,有效应对了大规模用户同时发起红包和抢红包请求时的高并发问题。该架构不仅提高了系统的处理能力和扩展性,还保证了各个单元的独立性和高容错性,确保了系统在高峰期依然能够稳定运行。

解决方案要素二:红包系统的数据库并发问题

针对数据库(DB)并发问题,有三个层次的解决方案:逻辑 Server 排队机制、单机请求排队方案、Redis 并发控制,目标是避免数据库在并发高峰时出现“抢锁”问题:

逻辑 Server 层请求排队机制

红包系统作为资金交易系统,必须保证数据库事务的完整性和一致性。在处理红包时,每个红包涉及金额的分配和领取,这些操作会锁定数据库的资源进行处理。如果大量并发请求同时访问数据库,就会出现“抢锁”问题,影响系统的性能和稳定性。

思路假如这些操作不是并发的,而是串行的(一个接一个地处理),就能有效避免“抢锁”问题。因此,在系统中,我们通过将同一红包 ID 的请求按FIFO(先进先出)排队的方式,确保每个红包的相关请求以串行的方式进入数据库。

实现方式

  • 每个红包有唯一的 ID,系统根据红包 ID,将所有与此红包相关的请求固定在同一台逻辑 Server 上处理。
  • 这样,即便在同一个 SET 单元中有多个服务器,由于该红包的请求被定向到同一台 Server,确保同一红包的所有事务操作按顺序执行,避免了并发问题。
单机请求排队机制

在上述基础上,系统设计了进一步的机制——单机请求排队方案,将分配到同一台 Server 上的请求按红包 ID 排队。具体步骤如下:

  • 每当一个 Server 收到请求时,会首先根据红包 ID 进行排队。
  • 然后,排队的请求依次传递给 Server 内部的 worker 进程(业务处理逻辑),确保每个 worker 进程只处理一个红包相关的请求。
  • 这样,所有与某个红包相关的事务都会串行地进入数据库,确保数据库的操作是顺序执行的,不会出现抢锁现象。

示意图单台服务器的请求处理队列如同生产线,每个请求按顺序排队,排队的请求逐个进入业务逻辑执行层。

Redis 缓存层控制并发

为了进一步增强并发控制,系统引入了 Redis 缓存,特别是在应对并发量巨大时。具体措施如下:

  • Redis 的 CAS(Compare-And-Swap)操作:Redis 通过 CAS 原子累加操作,控制同时进入数据库的请求数量。对于同一红包,如果有多个并发请求,Redis 会控制同时执行的数量,确保超过一定数量的请求直接拒绝或者延迟处理。

  • 负载均衡和降级保护:如果系统检测到数据库的负载过高,Redis 缓存会起到降级作用,拒绝过多的并发请求,避免数据库崩溃或严重超载。

通过 Redis 的并发控制机制避免高并发情况下,所有请求直接压到数据库层,防止系统的雪崩效应。

这套解决方案通过三个核心措施——逻辑 Server 排队机制、单机请求排队方案、Redis 并发控制,解决红包系统的数据库并发问题:

  • 逻辑 Server 排队机制确保红包的所有请求都定向到同一台服务器,避免并发操作。
  • 单机请求排队方案确保同一服务器上的请求按顺序处理,实现拆红包的事务串行化。
  • Redis 控制并发在高负载情况下,通过缓存层控制请求数量,避免数据库崩溃。

这些措施有效地保证了微信红包系统在高并发环境下的稳定性和性能,使得系统可以在用户数激增的节假日等场景下,依然能流畅运行。

解决方案要素三:双维度分库分表设计

系统初期,红包系统采用基于红包 ID 的 hash 值来进行数据分库分表。每个红包都有一个唯一的 ID,系统根据这个 ID 的 hash 值将红包数据存储到不同的数据库和表中。例如,某个红包的 ID 经过 hash 计算后,可能被存储到 db_01.t_02 表中。

然而,随着系统用户量和红包数据量的不断增加,单个数据库和表中的数据量也迅速膨胀。数据量过大会导致以下问题:

  • 查询效率下降:单表数据量增大,查询和写入的性能逐渐下降,影响系统的响应速度。
  • 数据库瓶颈:数据库的存储和处理能力有限,当单表数据量超出一定阈值时,数据库性能会大幅下降,可能导致请求超时或者系统崩溃。
冷热数据分离

为了应对这些问题,微信红包系统引入了冷热数据分离的策略。即将历史冷数据当前热数据进行分开存储和处理。

  • 热数据:指的是近期的、正在使用的红包数据,例如用户正在发的红包、抢的红包等。这部分数据的访问频率较高,需要快速响应。
  • 冷数据:指的是历史上的、已经很少被访问的红包数据。这类数据访问频率较低,可以存放在性能较低的存储中,以降低数据库负载。

通过将历史冷数据和当前热数据分离存储,可以有效减少单个数据库中的数据量,提升数据库的查询和写入效率。

双维度分库分表设计

在实现冷热数据分离的基础上,微信红包系统进一步提出了双维度分库分表的设计。这个设计结合了红包 ID 和日期的双重维度,形成更加细致的分库分表规则:

  • 红包 ID 维度:首先,系统根据红包 ID 的 hash 值,将数据水平切分到多个数据库和表中。例如,红包 ID 的 hash 值的后三位用来决定分配到哪个库表中(如 db_01.t_02)。
  • 日期维度:同时,系统根据日期(天)进行分表。一个月最多有 31 天,系统会根据红包创建的日期进一步将数据存储到对应的表中。例如,dd 代表天数,取值范围为 01~31,表示一个月中的具体天。

数据库表结构示例为:db_xx.t_y_dd,其中:

  • xx 表示红包 ID 的 hash 值,用于选择分库。
  • y 表示红包 ID 的 hash 值,用于选择具体的表。
  • dd 表示日期,用于根据天进行分表。

这种双维度分库分表设计,主要有以下几个优势:

  1. 减少单表数据量:通过红包 ID 和日期的双重维度切分,确保单个表中的数据量保持在合理范围内,避免单表数据量过大导致的性能问题。
  2. 查询效率提升:当前活跃的热数据与历史冷数据分离存储,可以快速查询当前数据,同时将历史数据存储到性能较低的数据库中,减少数据库的压力。
  3. 热冷数据迁移简便:双维度设计使得热数据和冷数据之间的迁移更加灵活。只需要基于日期将数据进行归档和迁移操作即可,不会影响现有系统的运行。
  4. 扩展性好:随着业务量的增加,可以通过增加数据库和表的数量来实现水平扩展。这种双维度切分的方式,可以轻松适应数据量的持续增长。

通过采用双维度分库分表设计,微信红包系统有效解决了因单表数据膨胀导致的数据库性能下降问题。在高并发场景下,该设计保证了系统能够快速响应用户请求,确保了性能的稳定性。同时,通过冷热数据分离策略,实现了数据存储的灵活性和系统扩展性,为大规模红包发放场景下的稳定运行提供了保障。

这套方案的设计思路,结合了红包 ID 和日期的双重维度,使得数据库的查询和写入操作更加高效,同时也为历史数据的管理提供了便捷的解决方案,使得系统不仅能承受大量用户的并发访问,还能确保长时间运行的稳定性。

(四)红包分配算法分析:揭秘如何让抢红包更刺激!

抢红包是春节里最有趣的活动之一,谁不想在一堆红包里捡到“大奖”呢?其背后系统是如何决定你能抢到多少钱的?

实时拆分:每次都随机分配

当你点开一个红包的时候,系统并不是早就决定好了你能抢到多少钱,而是实时计算的。这种算法叫做实时拆分,每个红包金额在你点击时才生成。

有个简单但聪明的办法叫二倍均值法。这个名字听起来很高深,其实背后的原理很简单:

  • 想象一下,你面前有一个红包,里面总共有 10 元,还剩 5 个人没抢。系统会先算出平均每个人能抢到 2 元(10 ÷ 5 = 2)。然后系统说:“我给你一个随机数,这个数在 0.01 元到 4 元之间,抢多少看运气!”

这就是二倍均值法:你每次能抢到的金额范围在 0.01 元到剩下金额的 2 倍平均值之间。这让每次抢红包都充满了不确定性,也让大额红包变得格外惊喜!

为什么要保证随机?

我们喜欢抢红包的原因之一就是它的随机性。你可能一分钱没抢到,也可能幸运地抢到比别人多好几倍的金额。这种不可预测性增加了乐趣。

但为了防止最后一个人只抢到 0.01 元这样令人尴尬的情况,系统会提前预留出一些金额。比如总共有 10 个红包,系统会先扣除 0.01 元 × 10 个红包 的保底金额,确保每个人至少能抢到 0.01 元。这样,最后一个人拿到的金额也不会太少。

实际中的小秘密

你可能发现过,当红包金额比较小的时候,最后一个人经常会抢到一个比别人大的金额。这是因为系统在派发红包时,最小值是固定的(0.01 元),而系统会调整每次分配的金额,使得最后一个人不会被剩余的小金额“坑”到。

举个简单的例子:假设你发了总额为 0.04 元的 3 个红包。系统先把 3 × 0.01 元 放到“安全垫”里,这样前两个人抢到的金额都会是 0.01 元,剩下的金额就留给最后一个人。

看一下代码是怎么实现的

用二倍均值法来分配红包的算法很简单,可以用 Java 实现一个类似的“二倍均值法”来分配红包。

package org.zyf.javabasic.algorithm;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @program: zyfboot-javabasic
 * @description: 实现一个类似的“二倍均值法”来分配红包
 * @author: zhangyanfeng
 * @create: 2024-09-19 10:32
 **/
public class RedEnvelope {
    // 保留两位小数
    public static double remainTwoDecimal(double num) {
        return Math.round(num * 100.0) / 100.0;
    }

    // 随机获取红包金额
    public static double getRandomRedPack(RedPack rp) {
        if (rp.getSurplusTotal() <= 0) {
            // 所有红包都已经分配完毕
            return 0;
        }

        // 如果是最后一个红包,直接返回剩余金额
        if (rp.getSurplusTotal() == 1) {
            return remainTwoDecimal(rp.getSurplusAmount());
        }

        Random rand = new Random();

        // 计算剩余平均金额
        double avgAmount = remainTwoDecimal(rp.getSurplusAmount() / rp.getSurplusTotal());

        // 最大可分配金额为 2 倍均值 - 0.01
        double max = remainTwoDecimal(2 * avgAmount - 0.01);

        // 随机生成红包金额
        double money = remainTwoDecimal(rand.nextDouble() * max + 0.01);

        // 更新剩余金额和剩余红包数量
        rp.setSurplusTotal(rp.getSurplusTotal() - 1);
        rp.setSurplusAmount(remainTwoDecimal(rp.getSurplusAmount() - money));

        return money;
    }

    // 测试函数
    public static void main(String[] args) {
        RedPack rp = new RedPack(10.00, 5); // 初始化:总金额 10 元,5 个红包

        List<Double> redPacks = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            double money = getRandomRedPack(rp);
            redPacks.add(money);
        }

        System.out.println("每个红包的金额为:");
        for (double amount : redPacks) {
            System.out.println(amount + " 元");
        }
    }
}



package org.zyf.javabasic.algorithm;

/**
 * @program: zyfboot-javabasic
 * @description: 实现一个类似的“二倍均值法”来分配红包
 * @author: zhangyanfeng
 * @create: 2024-09-19 10:31
 **/
public class RedPack {
    private double surplusAmount; // 剩余金额
    private int surplusTotal; // 红包剩余个数

    public RedPack(double surplusAmount, int surplusTotal) {
        this.surplusAmount = surplusAmount;
        this.surplusTotal = surplusTotal;
    }

    public double getSurplusAmount() {
        return surplusAmount;
    }

    public int getSurplusTotal() {
        return surplusTotal;
    }

    public void setSurplusAmount(double surplusAmount) {
        this.surplusAmount = surplusAmount;
    }

    public void setSurplusTotal(int surplusTotal) {
        this.surplusTotal = surplusTotal;
    }
}

(五)高可用解决方案分析

红包系统可以通过微服务、无状态设计、冗余部署、SET 化等方式,确保高并发场景下的稳定性和可用性。核心逻辑简化,非关键操作异步化,故障自动处理,保障业务持续运行。整体的思路可直接总结成如下几个方面:

  • 系统架构分离

    • 信息流、业务流、资金流分离:分别处理不同业务,模块化提升维护性。
    • 微服务架构:每个服务负责单一功能,故障隔离,扩展性强。
    • 无状态服务:服务不依赖本地数据,提升并发和容灾能力。
  • 高可用策略

    • 冗余部署:多地多机房部署,关键节点有备份,自动接管故障服务。
    • 负载均衡:流量分发均衡,防止单点过载。
    • 容器化:使用 Docker、Kubernetes,快速部署和弹性扩展。
  • 数据层优化

    • 数据备份与恢复:定期备份,确保快速恢复。
    • 分布式缓存:Redis 等缓存技术,减少数据库压力。
    • 分布式锁:确保红包领取操作的原子性,避免多次领取。
  • 异步化设计

    • 关键路径最简化:只在抢红包时执行必要步骤,写账单、入账等操作异步处理。
    • MQ 异步执行:使用消息队列处理非关键步骤,确保性能和数据最终一致。
  • 故障处理与扩容

    • SET 化订单存储:订单按编号分库,故障隔离,确保一部分故障不影响整体业务。
    • 自愈设计:当 DB 故障时自动跳过,换号生成,确保业务不中断。
  • 监控与告警

    • 实时监控:关键指标监控,防止故障蔓延。
    • 告警通知:异常时及时通知运维人员。

三、系统扩展分析:平衡扩容问题

从图片可以看出,这张图展示了红包存储层平行扩容的架构设计:

(一)搭建新 SET

  • 图中的每一个分支代表了一个 SET,即红包数据库集群的分组,每个 SET 有自己的主从数据库(Master-Slave),用于存储和处理订单数据。
  • 当系统的订单量增加,需要扩展时,可以增加新的 SET,如图右侧的 SET 010,从而实现平行扩容。

(二)逻辑服务根据订单号分配到对应 SET

  • 在订单生成时,业务逻辑服务会根据订单号的倒数几位(如图片中的 XXX),将订单分配到不同的 SET 中。
  • 每个 SET 的请求只处理自己分配到的订单,不会互相影响,这样保证了数据库间的隔离性和并发处理能力。

(三)请求路由与数据库故障自愈

  • 如果某个 SET(如图中 SET 009)发生故障,系统可以通过调整路由策略,将新订单号分配到其他可用的 SET 中,比如 SET 010
  • 这种方式不仅保证了系统的高可用性,还避免了故障 SET 的影响扩散。

通过这种 SET 化红包号分段路由 的设计,系统可以实现 按需扩展,并且在某个数据库集群出现故障时,其他部分仍然可以正常运作,保证了红包系统在高并发情况下的稳定性和可扩展性

这个思路让系统的扩容更加灵活,避免了传统架构中单点故障可能导致的系统宕机。

四、总结

微信红包系统的成功在于其精密的架构设计和高效的技术实现,尤其是在面对高并发和海量数据处理的挑战时。系统通过精细的功能模块划分,从接入层到业务逻辑层,再到数据存储和分析层,确保了用户体验的流畅性和资金的安全性。针对高并发问题,采用了单元化架构和双维度分库分表设计,有效提高了系统的处理能力和扩展性。同时,Redis 缓存和异步处理机制进一步优化了性能,防止了数据库的过载。

在红包分配算法上,实时拆分和二倍均值法为用户带来了随机而公平的抢红包体验,而保底金额机制避免了最后一个红包金额过少的尴尬。为了确保系统的高可用性,通过微服务架构、无状态设计、冗余部署等手段,保证了系统在极端条件下的稳定性和容灾能力。

总的来说,微信红包系统的设计不仅解决了高并发场景下的技术难题,还提供了优质的用户体验。这一成功案例展示了现代大型分布式系统如何通过创新的技术和架构设计应对复杂的业务需求和挑战。

参考文章

架构实战营第二课作业——微信朋友圈的高性能复杂度分析_架构实战营_tt_InfoQ写作社区

微信朋友圈技术之道:三个人的后台团队与每日十亿的发布量_语言 & 开发_陈明_InfoQ精选文章

132. 红包系统架构设计_红包系统设计-CSDN博客

图解:红包系统架构设计

百亿级流量红包系统,如何做架构?(字节面试真题) - 疯狂创客圈 - 博客园

微信红包后台系统设计-腾讯云开发者社区-腾讯云

如何搭建一个红包架构?-腾讯云开发者社区-腾讯云

微信高并发资金交易系统设计方案-----百亿红包背后的技术支撑 | Hexo

(二)微信红包架构、抢红包算法和高并发和降级方案(2) - 简书

微信红包的支撑架构原理是什么?_微信红包架构设计-CSDN博客

微信红包技术架构设计 微信抢红包架构_mob64ca1414098d的技术博客_51CTO博客

评论 765
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张彦峰ZYF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值