279 这一类模式的组织方式很有意思:每个点位下面只允许挂两个子位(左区/右区),用户按注册或下单顺序进关系网,推荐人双区满了就把新进来的人"滑落"到下级空闲位置,整体凑成固定规模的团队后出局并循环。它本质上是一棵受约束的二叉树,加一个排队滑落调度器,再加一套状态机管出局与重排。本文从开发视角拆这套二叉关系网怎么落地。
目录
- 279 模式的关系网长什么样
- 把关系网写成平铺用户表的天花板
- 技术本质:二叉树 + 排队滑落 + 状态机
- 数据支撑,标出处
- 二二复制与自由多叉树对比
- 关键组件矩阵
- 落地步骤与代码
- 边界与风险
一、279 模式的关系网长什么样
先看结构。关系网是一棵二叉树:每个节点至多两个子位,约定为左区和右区。新用户注册或下单后进入排队,关系网按"先挂推荐人、双区满再滑落"的规则把人落到某个空位上。当某个子树凑满固定规模(常见为七人:1 个根加左右 2 个、再各带 2 个共 7 个),根节点成团出局,并按"下帮上、左帮右"的规则重新占位,进入下一轮。
滑落是这套结构的关键动作:推荐人直推超过双区容量时,超出的人不丢,而是沿推荐人的关系网向下找首个空闲指定区填进去,填进去那一刻,那个空位的直接上级拿到滑落奖。规则本身可以归纳成三条:直推优先、从上到下、从左到右,并且只填约定区(如只填左区)。
[1号]
/ \
[2号] [3号]
/ \ / \
[4] [5] [6] [7] 七人团:1号成团出局
↑
滑落示意:1号直推第4人,2号双区已满,则滑落到2号名下
首个空闲左区(即 [4] 位),2号获得滑落奖
这张图是整篇主线:二叉树管结构,排队滑落管占位,状态机管出局与循环。
二、把关系网写成平铺用户表的天花板
很多团队初期把"谁推荐谁"存成一张用户表:user.sponsor_id、user.zone。这种写法有三个工程痛点,放到二二复制场景会被放大。
其一,约束表达不了。二二复制要求每点严格两个子位,平铺表只能靠应用层自觉,哪天写错一个 zone 就变成三子位,结构被破坏却无感知。
其二,滑落逻辑散落。滑落要同时满足"直推优先、从上到下、从左到右、只填某区",用一堆 UPDATE 拼出来,条件一多就容易错位,明明该填左区却填了右区,账目就乱了。
其三,出局状态无统一机。成团、出局、重排如果没有状态机兜底,常见 bug 是重复出局、漏发奖、循环占位时死循环。关系网的完整性必须靠状态转移来保障,不能靠业务逻辑里到处 if。
要破这三件事,得把关系网抽象成"二叉树节点 + 占位调度器 + 节点状态机"三个独立模块。
三、技术本质:二叉树 + 排队滑落 + 状态机
二叉树节点负责把"每点两子位"的约束固化进数据结构;占位调度器负责排队与滑落寻位;状态机负责节点从待激活到成团到出局再到重排的转移。三者解耦,逻辑才清楚。
节点结构:每点固定两子位。 把约束写进类,越界挂接点直接报错而非静默成功。
# 二叉关系网节点:每个点位至多 2 个子位(左区/右区)
class Node:
def __init__(self, uid, sponsor=None):
self.uid = uid
self.sponsor = sponsor # 推荐人 uid
self.left = None # 左区子位
self.right = None # 右区子位
self.status = "active" # active / out(出局) / requeued(重排)
self.team_size = 0 # 冗余:子树活跃点位计数
def free_zone(self):
"""返回首个空闲区名,满则返回 None(触发滑落)"""
if self.left is None: return "left"
if self.right is None: return "right"
return None
占位调度:先挂推荐人,双区满则滑落。 有推荐人先直推左右区,满了再 BFS 找下级首个空闲约定区;无推荐人则全网随机占位。
# 占位:推荐人优先,双区满则向下滑落(仅填约定区)
def place(root, new_uid, sponsor_uid, slide_zone="left"):
sponsor = find_node(root, sponsor_uid)
if sponsor is None:
return random_place(root, new_uid) # 无推荐人:全网随机占位
zone = sponsor.free_zone()
if zone: # 直推优先:左/右区有空直接挂
setattr(sponsor, zone, Node(new_uid, sponsor.uid))
return {"parent": sponsor.uid, "zone": zone, "bonus": "refer"}
slot = find_empty_slot(sponsor, slide_zone) # 双区满 → 滑落寻位
if slot is None:
return random_place(root, new_uid)
setattr(slot, slide_zone, Node(new_uid, slot.uid))
return {"parent": slot.uid, "zone": slide_zone, "bonus": "slide"} # slot 上级拿滑落奖
滑落寻位:广度优先,从上到下、从左到右。 只填约定区,确保滑落确定可复现。
# 滑落寻位:BFS 从上到下、从左到右,只填指定区
from collections import deque
def find_empty_slot(subtree, zone="left"):
q = deque([subtree])
while q:
cur = q.popleft()
if getattr(cur, zone) is None:
return cur # 找到首个空闲约定区
if cur.left: q.append(cur.left)
if cur.right: q.append(cur.right)
return None
成团判定:子树满固定规模即出局。 用冗余计数避免每次全树遍历,规模阈值可配置(常见七人团)。
# 成团判定:子树活跃点位达阈值即视为成团
TEAM_SIZE = 7
def count_active(node):
if node is None: return 0
return 1 + count_active(node.left) + count_active(node.right)
def check_team(node):
node.team_size = count_active(node) # 落地时改冗余字段增量维护
return node.team_size >= TEAM_SIZE
状态机:出局与重排的转移必须收敛。 事件驱动,防止重复出局与无限循环占位。
# 状态机:active → team → out → requeued(下帮上重排)
def transition(node, event):
if node.status == "active" and event == "team_full":
node.status = "team" # 成团
elif node.status == "team" and event == "settle":
node.status = "out" # 出局,结算成团点位收益
elif node.status == "out" and event == "requeue":
node.status = "requeued" # 下帮上、左帮右重新占位
else:
raise ValueError(f"非法转移: {node.status} --{event}-->")
return node.status
循环奖励:推荐收益按单序交替。 首单 20%、次单 80%,之后按单序 20%/80% 交替,是这套模式常见的发放节奏。
# 推荐收益:首单 20%、次单 80%,按单序交替发放
def referral_reward(order_seq, amount):
"""order_seq 从 1 起;奇序 20%,偶序 80%"""
rate = 0.20 if order_seq % 2 == 1 else 0.80
return round(amount * rate, 2)
# 例:金额 1000 时,第1单 200、次单 800、第三单 200、第四单 800…
print([referral_reward(i, 1000) for i in range(1, 5)])
引擎配置。 把容量、滑落区、成团规模、奖励节奏外置,规则不硬编码进业务。
{
"engine": "mode_279",
"zones_per_node": 2,
"slide_zone": "left",
"team_size": 7,
"referral_rates": [0.20, 0.80],
"slot_bonus": 50,
"team_bonus": 100,
"placement": "sponsor_first_then_slide"
}
四、数据支撑,标出处
社交电商与私域经营已是可观市场,关系网类玩法才有落地土壤。据网经社《2023 中国私域电商市场数据报告》,当年私域电商市场规模约 5.8 万亿元、用户约 4.5 亿。另据 CNNIC 第 56 次《中国互联网络发展状况统计报告》,截至 2025 年 6 月网民规模 11.23 亿、互联网普及率 79.7%。不同机构口径有差异,数字宜看作趋势参考而非精确结论。
二二复制加自动滑落,是社交电商里常见的组织形态,优势在于关系网浅、占位确定、成团易判定。行业里也有循环复购跑出规模的公开运营复盘(某商城用相近机制 8 个月做到 300 万活跃会员),说明这类结构在拉新与复购上的确有效。需要说明:本文第三节的成团规模、奖励比例、滑落区等来自行业常见配置示例,用于把机制讲实,并非任一平台的标准参数,实际取值由运营与合规共同决定。
五、二二复制与自由多叉树对比
| 维度 | 二二复制(二叉约束) | 自由多叉树 |
|---|---|---|
| 组织深度 | 收敛快 | 易失控 |
| 滑落确定性 | 强(规则明确) | 弱 |
| 成团判定 | 简单(满 N 即团) | 复杂 |
| 合规压力 | 关系网浅 | 易做深 |
| 系统复杂度 | 中(需调度器) | 低但难控 |
工程上,二二复制用结构约束换来了可判定性:成团就是"满 7 个",滑落就是"BFS 首个空位",逻辑可测试、可复现。自由多叉树写起来省事,但后期占位和结算全靠业务兜,账目极易错乱。
六、关键组件矩阵
| 组件 | 职责 | 优势 | 劣势 |
|---|---|---|---|
| 关系网存储 | 二叉树持久化 | 结构清晰 | 深链查询开销 |
| 占位调度 | 排队 + 滑落 | 公平确定 | 需并发控制 |
| 滑落引擎 | 寻位算法 | 可复现 | 规则分支多 |
| 成团判定 | 满员检测 | 自动触发 | 需计数优化 |
| 状态机 | 转移管理 | 防重复出局 | 事件需穷举 |
| 收益结算 | 奖励发放 | 透明 | 须幂等 |
六个组件里,占位调度和收益结算容易被低估。前者决定两个人会不会抢同一个空位,后者决定同一次成团会不会发两次奖——两者都必须在事务与锁的边界内解决。
七、落地步骤与代码
占位要原子。占位动作包含"读推荐人双区状态、读下级空位、写入新节点"三步,高并发注册若不加约束,会出现两人同时看到同一个空位、各写一次,二叉树被悄悄破坏。做法是在推荐人维度加分布式锁,或把"寻找空位 + 写入"合成单条数据库条件更新(仅当目标区为 NULL 时才写入),让数据库确保原子。
滑落要幂等。一次注册只应占位一次,重试不能重复挂节点、重复发奖。用"注册单号 + 状态机"约束:同一单只能从"待占位"转到"已占位"一次,占位与收益发放放在同一事务内。
成团计数要增量。每次成团都 count_active 全树遍历,深树会拖垮性能。落地时用冗余字段 team_size,在每次占位时沿祖先链 +1,出局重排时回滚,读判定直接取值。
关系网深度要收敛。二二复制天然浅,但滑落可能把人推到很深的叶子。设定上限深度阈值,超深时回退到全网随机占位,避免链过长导致查询与重排成本爆炸。
八、边界与风险
泼一点冷水,工程上要想清楚几件事。
并发占位竞态。双区同占、滑落同位是头号 bug,必须用锁或条件更新兜住,否则关系网静默损坏,后续成团与结算全错。
滑落规则歧义。只填某区还是双区都可填、是从上到下还是按收益优先,规则一句话定不清,代码就会分叉。规则必须写成配置(第三节的 slide_zone),全员按同一份执行。
成团计数性能。深树全量遍历在高峰会卡,冗余计数能解,但要处理"占位与计数回滚"的一致性,重排时别忘了把祖先链计数减回去。
出局循环依赖。出局后"下帮上、左帮右"重排,如果规则没写好,可能出现 A 补 B、B 又补 A 的环,或者无限占位。状态机(第三节 transition)要把"重排"设为终态事件,触发后必须落定,不允许再被二次滑落。
合规边界。关系网深度收敛、奖励收敛在直推与滑落两级,不向下做无限层级计酬,是这类模式能稳健运行的前提,与前面几篇讲过的合规要求一致。具体边界以法务意见为准,技术侧只确保结构不越界。
数据一致性。占位、成团、发奖三者必须同事务:占位成功但发奖失败要整体回滚,否则漏奖或双奖都会出现。把状态机作为统一写入口,能从架构上挡住大部分错账。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/luoanan8899/article/details/167471387




