一、引言:平台化能力的价值
在互联网产品进入存量竞争的时代,平台的整体能力决定了产品能否快速响应业务需求、能否精细化运营用户、能否持续迭代增长。一个功能完备的平台底座,不仅需要支撑核心业务流程,更需要提供用户分群、跨平台联运、A/B测试、运营位管理等横向能力。
这些能力看似独立,实则共同构成了一个完整的产品运营闭环:
用户分群 (谁)→ 运营位投放 (在哪)→ ABTest验证 (效果)→ 联运分流 (量级分配)→ 数据反馈 → 策略优化
本文将从后端工程视角,系统阐述这四大模块的设计与实现,构建一个可扩展的平台能力体系。
二、系统整体架构
平台能力层位于业务服务层之上,为上层业务提供通用的运营和策略能力,各能力模块以独立微服务形式部署,通过统一配置中心和消息总线实现联动。
┌─────────────────────────────────────────────────────────────────────┐
│ 业务应用层 │
│ App首页 │ 搜索页 │ 活动页 │ 内容详情 │ 个人中心 │ 支付页 │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 平台能力层(本文核心) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
│ │用户分群 │ │ABTest │ │运营位 │ │联运分流 │ │配置中心 │ │
│ │服务 │ │服务 │ │管理 │ │服务 │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 基础设施层 │
│ MySQL │ Redis │ 消息队列 │ 监控 │ 日志 │ 数据仓库 │
└─────────────────────────────────────────────────────────────────────┘
三、用户分群系统
用户分群是精细化运营的基础。通过对用户进行多维度的标签划分,实现"千人千面"的差异化服务。
3.1 分群模型设计
分群模型基于标签体系构建,支持动态和静态两种分群方式。
python
# user_segment.py - 用户分群核心模型
from typing import List, Dict, Any, Optional
from enum import Enum
from datetime import datetime, timedelta
import json
import redis
import hashlib
class SegmentType(Enum):
"""分群类型"""
STATIC = "static" # 静态分群:手动圈选,固定不变
DYNAMIC = "dynamic" # 动态分群:基于规则实时计算
PREDICTIVE = "predictive" # 预测分群:基于模型预测
class SegmentCondition:
"""分群条件"""
def __init__(self, field: str, operator: str, value: Any):
self.field = field # 用户字段: age, city, last_active, etc.
self.operator = operator # 操作符: eq, neq, gt, lt, in, contains
self.value = value # 比较值
def evaluate(self, user: Dict) -> bool:
"""评估用户是否满足条件"""
user_value = user.get(self.field)
if user_value is None:
return False
if self.operator == 'eq':
return user_value == self.value
elif self.operator == 'neq':
return user_value != self.value
elif self.operator == 'gt':
return user_value > self.value
elif self.operator == 'lt':
return user_value < self.value
elif self.operator == 'in':
return user_value in self.value
elif self.operator == 'contains':
return self.value in user_value
elif self.operator == 'between':
return self.value[0] <= user_value <= self.value[1]
return False
class UserSegment:
"""用户分群定义"""
def __init__(self, segment_id: str, name: str,
segment_type: SegmentType = SegmentType.DYNAMIC):
self.id = segment_id
self.name = name
self.type = segment_type
self.conditions: List[SegmentCondition] = []
self.conditions_operator = 'AND' # AND / OR
self.member_count = 0
self.created_at = datetime.now()
self.updated_at = datetime.now()
self.is_active = True
def add_condition(self, field: str, operator: str, value: Any):
"""添加分群条件"""
self.conditions.append(SegmentCondition(field, operator, value))
self.updated_at = datetime.now()
def is_member(self, user: Dict) -> bool:
"""判断用户是否属于该分群"""
if not self.conditions:
return True
if self.conditions_operator == 'AND':
return all(c.evaluate(user) for c in self.conditions)
else: # OR
return any(c.evaluate(user) for c in self.conditions)
3.2 分群服务实现
分群服务负责分群的CRUD、成员计算和实时判定。
python
# segment_service.py - 分群服务
from typing import List, Dict, Set, Optional
import asyncio
from concurrent.futures import ThreadPoolExecutor
class SegmentService:
"""用户分群服务"""
def __init__(self, redis_client: redis.Redis, db_session):
self.redis = redis_client
self.db = db_session
self.executor = ThreadPoolExecutor(max_workers=10)
self.segment_cache = {}
self.cache_ttl = 300 # 5分钟
def create_segment(self, name: str, conditions: List[Dict],
segment_type: str = 'dynamic') -> UserSegment:
"""创建分群"""
segment_id = f"seg_{hashlib.md5(name.encode()).hexdigest()[:8]}"
segment = UserSegment(segment_id, name, SegmentType(segment_type))
for cond in conditions:
segment.add_condition(
cond['field'],
cond['operator'],
cond['value']
)
# 存储到数据库
self._save_to_db(segment)
# 如果是静态分群,立即计算成员
if segment.type == SegmentType.STATIC:
self._compute_static_members(segment)
return segment
def get_user_segments(self, user_id: str) -> List[str]:
"""获取用户所属的所有分群"""
# 先查缓存
cache_key = f"user_segments:{user_id}"
cached = self.redis.get(cache_key)
if cached:
return json.loads(cached)
# 获取用户画像
user = self._get_user_profile(user_id)
if not user:
return []
# 遍历所有分群
segments = self._get_all_segments()
matched = []
for segment in segments:
if segment.is_active and segment.is_member(user):
matched.append(segment.id)
# 缓存结果
self.redis.setex(cache_key, 300, json.dumps(matched))
return matched
def get_segment_users(self, segment_id: str,
page: int = 1, size: int = 100) -> Dict:
"""获取分群下的用户列表"""
segment = self._get_segment(segment_id)
if not segment:
return {"users": [], "total": 0}
if segment.type == SegmentType.STATIC:
# 从Redis获取预计算成员
key = f"segment:{segment_id}:members"
total = self.redis.scard(key)
members = self.redis.srandmember(key, size)
return {
"users": [self._get_user_profile(m) for m in members],
"total": total
}
else:
# 动态分群:实时计算
users = self._get_all_users()
matched = [u for u in users if segment.is_member(u)]
# 分页
start = (page - 1) * size
return {
"users": matched[start:start+size],
"total": len(matched)
}
def _compute_static_members(self, segment: UserSegment):
"""异步计算静态分群成员"""
def compute():
users = self._get_all_users()
members = [u['user_id'] for u in users if segment.is_member(u)]
# 存储到Redis Set
key = f"segment:{segment.id}:members"
self.redis.delete(key)
if members:
self.redis.sadd(key, *members)
self.redis.expire(key, 86400 * 7) # 7天
# 更新成员数量
segment.member_count = len(members)
self._update_segment(segment)
# 异步执行
self.executor.submit(compute)
def invalidate_user_cache(self, user_id: str):
"""用户信息变更时清除缓存"""
self.redis.delete(f"user_segments:{user_id}")
四、ABTest实验系统
A/B测试是数据驱动决策的核心工具。一个完善的ABTest系统需要支持多实验并行、流量正交、实时指标计算和科学统计。
4.1 ABTest核心模型
python
# abtest_model.py - ABTest核心模型
from typing import List, Dict, Any, Optional
from enum import Enum
from datetime import datetime
import hashlib
class ExperimentStatus(Enum):
DRAFT = "draft" # 草稿
RUNNING = "running" # 进行中
PAUSED = "paused" # 暂停
COMPLETED = "completed" # 已完成
ARCHIVED = "archived" # 已归档
class ExperimentType(Enum):
ABNORMAL = "abnormal" # A/B测试
MULTIVARIATE = "multivariate" # 多变量测试
CANARY = "canary" # 灰度发布
class Variation:
"""实验变体"""
def __init__(self, id: str, name: str, config: Dict, weight: int = 1):
self.id = id
self.name = name
self.config = config # 变体配置(JSON)
self.weight = weight # 流量权重
self.is_control = False # 是否为对照组
def to_dict(self) -> Dict:
return {
"id": self.id,
"name": self.name,
"config": self.config,
"weight": self.weight,
"is_control": self.is_control
}
class Experiment:
"""A/B实验"""
def __init__(self, exp_id: str, name: str, description: str = ""):
self.id = exp_id
self.name = name
self.description = description
self.status = ExperimentStatus.DRAFT
self.type = ExperimentType.ABNORMAL
# 流量配置
self.traffic_percentage = 10 # 实验占总流量的百分比
self.variations: List[Variation] = []
# 目标指标
self.metrics = [] # ["ctr", "conversion_rate", "revenue_per_user"]
# 分层与正交
self.layer = "default"
self.is_orthogonal = True
# 时间
self.start_time: Optional[datetime] = None
self.end_time: Optional[datetime] = None
self.created_at = datetime.now()
# 用户分群
self.target_segments: List[str] = [] # 限定实验人群
def add_variation(self, name: str, config: Dict, weight: int = 1,
is_control: bool = False):
"""添加变体"""
vid = f"var_{len(self.variations) + 1}"
var = Variation(vid, name, config, weight)
var.is_control = is_control
self.variations.append(var)
def assign_variation(self, user_id: str) -> Optional[Variation]:
"""为用户分配变体"""
if self.status != ExperimentStatus.RUNNING:
return None
# 检查用户是否在目标分群内
if self.target_segments:
user_segments = self._get_user_segments(user_id)
if not any(s in self.target_segments for s in user_segments):
return None
# 基于用户ID的哈希分流(保证一致性)
exp_key = f"{self.id}_{user_id}"
hash_val = int(hashlib.md5(exp_key.encode()).hexdigest(), 16)
# 判断是否在实验流量内
if hash_val % 100 >= self.traffic_percentage:
return None
# 计算分配到哪个变体
total_weight = sum(v.weight for v in self.variations)
if total_weight == 0:
return None
bucket = hash_val % total_weight
cumulative = 0
for var in self.variations:
cumulative += var.weight
if bucket < cumulative:
return var
return self.variations[0] if self.variations else None
4.2 ABTest服务实现
python
# abtest_service.py - ABTest服务
from typing import Dict, List, Optional, Any
import json
import redis
from datetime import datetime, timedelta
class ABTestService:
"""A/B测试服务"""
def __init__(self, redis_client: redis.Redis, db_session):
self.redis = redis_client
self.db = db_session
self.experiment_cache = {}
def create_experiment(self, name: str, description: str,
variations: List[Dict],
traffic_percentage: int = 10,
target_segments: List[str] = None) -> Experiment:
"""创建实验"""
exp_id = f"exp_{int(datetime.now().timestamp())}"
exp = Experiment(exp_id, name, description)
exp.traffic_percentage = traffic_percentage
exp.target_segments = target_segments or []
# 添加变体(第一个为对照组)
for i, var_config in enumerate(variations):
exp.add_variation(
name=var_config.get('name', f'变体{i+1}'),
config=var_config.get('config', {}),
weight=var_config.get('weight', 1),
is_control=(i == 0)
)
# 保存
self._save_experiment(exp)
return exp
def start_experiment(self, exp_id: str):
"""启动实验"""
exp = self._get_experiment(exp_id)
if not exp:
return False
exp.status = ExperimentStatus.RUNNING
exp.start_time = datetime.now()
self._save_experiment(exp)
self._clear_cache(exp_id)
return True
def get_variation(self, exp_id: str, user_id: str,
context: Dict = None) -> Dict:
"""获取用户的变体分配"""
exp = self._get_experiment(exp_id)
if not exp:
return {"experiment": exp_id, "variation": None, "is_control": True}
# 检查缓存
cache_key = f"abtest:{exp_id}:{user_id}"
cached = self.redis.get(cache_key)
if cached:
return json.loads(cached)
# 分配变体
var = exp.assign_variation(user_id)
result = {
"experiment": exp_id,
"variation": var.to_dict() if var else None,
"is_control": var.is_control if var else True
}
# 记录曝光
self._log_exposure(exp_id, user_id, var.id if var else None, context)
# 缓存结果(确保一致性)
self.redis.setex(cache_key, 3600, json.dumps(result))
return result
def get_experiment_results(self, exp_id: str) -> Dict:
"""获取实验结果"""
exp = self._get_experiment(exp_id)
if not exp:
return {}
# 从数据仓库查询指标
results = self._query_experiment_data(exp_id)
# 计算统计显著性
for metric in exp.metrics:
results[metric] = self._calculate_significance(
results.get(metric, {})
)
return results
def _calculate_significance(self, data: Dict) -> Dict:
"""计算统计显著性"""
# 使用T检验或贝叶斯方法
# 简化实现
control = data.get('control', {'mean': 0, 'std': 0, 'n': 0})
treatment = data.get('treatment', {'mean': 0, 'std': 0, 'n': 0})
if control['n'] == 0 or treatment['n'] == 0:
return {'significant': False, 'lift': 0}
# 计算提升率
if control['mean'] == 0:
lift = 0
else:
lift = (treatment['mean'] - control['mean']) / control['mean']
return {
'significant': abs(lift) > 0.05, # 简化判定
'lift': lift,
'confidence': 0.95
}
4.3 流量正交与分层
在大规模ABTest场景中,多个实验同时运行时需要确保流量正交,避免实验间相互干扰。
python
# traffic_orthogonal.py - 流量正交控制
class TrafficAllocator:
"""
流量分配器:支持多层流量正交
使用分层哈希确保各层实验独立
"""
def __init__(self, total_buckets: int = 10000):
self.total_buckets = total_buckets
self.layer_seeds = {} # 各层的随机种子
def register_layer(self, layer_name: str, seed: int = None):
"""注册实验层"""
if seed is None:
seed = hash(layer_name) % 2**32
self.layer_seeds[layer_name] = seed
def get_bucket(self, user_id: str, layer: str, exp_id: str = None) -> int:
"""获取用户在某层的流量桶号"""
if layer not in self.layer_seeds:
self.register_layer(layer)
# 使用层种子确保正交性
layer_seed = self.layer_seeds[layer]
key = f"{user_id}_{layer}_{exp_id or ''}"
hash_val = hashlib.md5(f"{key}_{layer_seed}".encode()).hexdigest()
return int(hash_val[:8], 16) % self.total_buckets
def is_in_experiment(self, user_id: str, layer: str,
exp_id: str, traffic_percentage: int) -> bool:
"""判断用户是否在实验流量内"""
bucket = self.get_bucket(user_id, layer, exp_id)
return bucket < self.total_buckets * traffic_percentage / 100
def assign_variation_in_layer(self, user_id: str, layer: str,
experiment: Experiment) -> Optional[Variation]:
"""在指定层中分配变体"""
# 流量正交判断
if not self.is_in_experiment(user_id, layer, experiment.id,
experiment.traffic_percentage):
return None
# 在层内分配变体
bucket = self.get_bucket(user_id, layer, experiment.id)
total_weight = sum(v.weight for v in experiment.variations)
bucket = bucket % total_weight if total_weight > 0 else 0
cumulative = 0
for var in experiment.variations:
cumulative += var.weight
if bucket < cumulative:
return var
return experiment.variations[0] if experiment.variations else None
五、运营位管理系统
运营位是平台进行内容推荐、活动推广和商业化变现的关键载体。一个成熟的运营位系统需要支持多端管理、动态投放、实时配置和效果追踪。
5.1 运营位模型
python
# operation_position.py - 运营位模型
from typing import List, Dict, Any, Optional
from enum import Enum
from datetime import datetime
import json
class PositionType(Enum):
BANNER = "banner" # Banner轮播
CARD = "card" # 卡片推荐
LIST = "list" # 列表插入
POPUP = "popup" # 弹窗
BUTTON = "button" # 按钮入口
ENTRANCE = "entrance" # 功能入口
class PositionStatus(Enum):
DRAFT = "draft"
ONLINE = "online"
OFFLINE = "offline"
EXPIRED = "expired"
class PositionContent:
"""运营位内容"""
def __init__(self, content_id: str, title: str, content_type: str):
self.id = content_id
self.title = title
self.type = content_type # image, text, video, mixed
self.data = {} # 内容数据
# 跳转配置
self.target_type = "" # url, app_page, mini_program
self.target_value = ""
# 样式配置
self.style = {} # 颜色、字体、尺寸等
self.priority = 0 # 优先级,数字越大越优先
class OperationPosition:
"""运营位定义"""
def __init__(self, position_id: str, name: str, position_type: PositionType):
self.id = position_id
self.name = name
self.type = position_type
# 位置信息
self.page = "" # 所在页面
self.slot = "" # 所在位置
self.order = 0 # 展示顺序
# 展示控制
self.max_items = 1 # 最多展示数量
self.display_mode = "single" # single / carousel / grid
# 定向配置
self.target_segments: List[str] = [] # 目标分群
self.target_platforms: List[str] = [] # iOS, Android, Web
# 内容列表
self.contents: List[PositionContent] = []
# 状态
self.status = PositionStatus.DRAFT
self.start_time: Optional[datetime] = None
self.end_time: Optional[datetime] = None
# 实验关联
self.abtest_exp_id: Optional[str] = None
5.2 运营位投放引擎
python
# position_engine.py - 运营位投放引擎
from typing import List, Dict, Any, Optional
import random
from collections import defaultdict
class PositionEngine:
"""运营位投放引擎"""
def __init__(self, redis_client: redis.Redis, segment_service, abtest_service):
self.redis = redis_client
self.segment_service = segment_service
self.abtest_service = abtest_service
self.position_cache = {}
def get_positions(self, page: str, user_id: str,
platform: str = "web",
context: Dict = None) -> Dict[str, List[Dict]]:
"""
获取页面所有运营位
返回: {position_id: [content1, content2, ...]}
"""
# 1. 获取页面配置的所有运营位
position_configs = self._get_page_positions(page)
if not position_configs:
return {}
result = {}
for pos_config in position_configs:
# 2. 检查运营位是否可用
if not self._is_position_available(pos_config):
continue
# 3. 检查用户定向
if not self._match_targeting(pos_config, user_id):
continue
# 4. 获取内容
contents = self._get_position_contents(pos_config, user_id, context)
if contents:
result[pos_config.id] = contents
return result
def _get_position_contents(self, position: OperationPosition,
user_id: str,
context: Dict) -> List[Dict]:
"""获取运营位内容(含ABTest)"""
# 如果关联了ABTest,使用实验分配的内容
if position.abtest_exp_id:
variation = self.abtest_service.get_variation(
position.abtest_exp_id,
user_id,
context
)
if variation and variation.get('variation'):
# 使用实验变体配置的内容
return self._get_contents_from_config(
variation['variation']['config'].get('contents', [])
)
# 正常投放:按优先级排序
sorted_contents = sorted(
position.contents,
key=lambda c: c.priority,
reverse=True
)
# 检查内容有效期
available = []
for content in sorted_contents:
if self._is_content_available(content):
available.append(content)
if len(available) >= position.max_items:
break
return [c.to_dict() for c in available]
def _match_targeting(self, position: OperationPosition, user_id: str) -> bool:
"""匹配定向条件"""
# 平台匹配
if position.target_platforms:
# 根据user_id获取平台信息
platform = self._get_user_platform(user_id)
if platform not in position.target_platforms:
return False
# 分群匹配
if position.target_segments:
user_segments = self.segment_service.get_user_segments(user_id)
if not any(s in position.target_segments for s in user_segments):
return False
return True
def _is_position_available(self, position: OperationPosition) -> bool:
"""检查运营位是否可用"""
if position.status != PositionStatus.ONLINE:
return False
now = datetime.now()
if position.start_time and now < position.start_time:
return False
if position.end_time and now > position.end_time:
return False
return True
def update_position_content(self, position_id: str,
content_data: Dict) -> bool:
"""实时更新运营位内容"""
position = self._get_position(position_id)
if not position:
return False
# 更新内容
content = PositionContent(
content_id=content_data['id'],
title=content_data['title'],
content_type=content_data['type']
)
content.data = content_data.get('data', {})
content.target_type = content_data.get('target_type', '')
content.target_value = content_data.get('target_value', '')
content.priority = content_data.get('priority', 0)
# 添加或替换
existing_idx = None
for i, c in enumerate(position.contents):
if c.id == content.id:
existing_idx = i
break
if existing_idx is not None:
position.contents[existing_idx] = content
else:
position.contents.append(content)
# 保存并清除缓存
self._save_position(position)
self._clear_cache(position_id)
return True
5.3 跨平台多端联动运营位
在App、搜索和活动平台之间实现运营位的统一管理和联动投放。
python
# cross_platform_position.py - 跨平台运营位联动
class CrossPlatformPositionManager:
"""
跨平台运营位联动管理
支持App、搜索、活动平台的内容联动
"""
def __init__(self, redis_client: redis.Redis, position_engine: PositionEngine):
self.redis = redis_client
self.position_engine = position_engine
def get_unified_positions(self, user_id: str,
platforms: List[str] = None,
context: Dict = None) -> Dict:
"""
获取跨平台的统一运营位
同一个运营位在不同平台展示一致或差异化内容
"""
platforms = platforms or ['app', 'search', 'activity']
result = {}
for platform in platforms:
# 获取平台对应的页面配置
pages = self._get_platform_pages(platform)
for page in pages:
positions = self.position_engine.get_positions(
page, user_id, platform, context
)
result[f"{platform}:{page}"] = positions
# 跨平台联动:统一内容策略
# 例如:用户在App上看到的活动,在搜索页也展示相同活动
result = self._apply_cross_platform_strategy(result, user_id)
return result
def _apply_cross_platform_strategy(self, positions: Dict,
user_id: str) -> Dict:
"""应用跨平台联动策略"""
# 获取用户跨平台行为
cross_actions = self._get_cross_platform_actions(user_id)
# 根据跨平台行为调整内容展示
for key, pos_data in positions.items():
platform = key.split(':')[0]
if platform == 'app' and cross_actions.get('search_clicked'):
# 用户在搜索点击了某内容,在App增加展示
self._boost_content(pos_data, cross_actions['search_clicked'])
if platform == 'search' and cross_actions.get('app_activity'):
# 用户在App参与了活动,搜索页展示相关推荐
self._add_related_content(pos_data, cross_actions['app_activity'])
return positions
def sync_position_across_platforms(self, position_id: str,
platform_data: Dict):
"""跨平台同步运营位配置"""
for platform, config in platform_data.items():
self.redis.setex(
f"position:{platform}:{position_id}",
3600,
json.dumps(config)
)
# 触发所有平台缓存更新
self._publish_update_event(position_id, platform_data)
六、联运分流系统
联运是平台聚合多方资源、实现流量价值最大化的关键手段。联运分流系统负责将用户流量合理分配给不同的联运合作伙伴。
python
# joint_operation.py - 联运分流系统
class JointOperationManager:
"""
联运分流管理器
支持多合作方流量分配、动态权重调整
"""
def __init__(self, redis_client: redis.Redis):
self.redis = redis_client
self.partners = {} # 合作方配置
self.weight_update_interval = 60 # 权重更新间隔(秒)
def register_partner(self, partner_id: str, name: str,
initial_weight: int = 1,
conditions: Dict = None):
"""注册联运合作方"""
self.partners[partner_id] = {
'id': partner_id,
'name': name,
'weight': initial_weight,
'conditions': conditions or {},
'total_allocations': 0,
'successful_conversions': 0,
'last_update': datetime.now()
}
def allocate_traffic(self, user_id: str, context: Dict) -> Optional[str]:
"""
为用户分配联运合作方
返回合作方ID
"""
# 获取可用的合作方列表
available = self._get_available_partners(user_id, context)
if not available:
return None
# 检查用户是否已被分配(保持一致性)
assigned = self._get_user_assignment(user_id)
if assigned and assigned in available:
return assigned
# 动态权重分配
weights = [p['weight'] for p in available]
total = sum(weights)
if total == 0:
return None
# 加权随机选择
rand_val = random.random() * total
cumulative = 0
for partner in available:
cumulative += partner['weight']
if rand_val < cumulative:
selected = partner['id']
break
else:
selected = available[0]['id']
# 记录分配
self._record_allocation(user_id, selected, context)
return selected
def update_partner_weight(self, partner_id: str, new_weight: int):
"""动态调整合作方权重"""
if partner_id not in self.partners:
return False
self.partners[partner_id]['weight'] = max(0, new_weight)
self.redis.setex(
f"partner_weight:{partner_id}",
86400,
new_weight
)
return True
def auto_adjust_weights(self):
"""根据转化率自动调整权重"""
total_conversions = sum(
p['successful_conversions'] for p in self.partners.values()
)
if total_conversions == 0:
return
for partner_id, partner in self.partners.items():
if partner['total_allocations'] == 0:
continue
conversion_rate = (
partner['successful_conversions'] /
partner['total_allocations']
)
# 相对转化率
avg_conversion = total_conversions / len(self.partners)
if avg_conversion == 0:
continue
relative_performance = conversion_rate / avg_conversion
# 调整权重(限制变化幅度)
new_weight = max(1, int(partner['weight'] * relative_performance * 0.8 + 0.2))
new_weight = min(100, new_weight)
self.update_partner_weight(partner_id, new_weight)
七、配置中心与灰度发布
平台能力需要灵活的配置管理和灰度发布机制来支持快速迭代。
python
# config_center.py - 配置中心
class ConfigCenter:
"""统一配置中心"""
def __init__(self, redis_client: redis.Redis,
fallback_config_path: str = None):
self.redis = redis_client
self.fallback_config_path = fallback_config_path
self.local_cache = {}
def get_config(self, key: str, default: Any = None,
user_id: str = None) -> Any:
"""
获取配置(支持用户级灰度)
"""
# 1. 用户级配置(灰度)
if user_id:
user_config_key = f"config:user:{user_id}:{key}"
val = self.redis.get(user_config_key)
if val is not None:
return self._deserialize(val)
# 2. 实验级配置
# 3. 全局配置
global_key = f"config:global:{key}"
val = self.redis.get(global_key)
if val is not None:
return self._deserialize(val)
# 4. 回退到本地配置
if self.fallback_config_path:
return self._load_fallback_config(key, default)
return default
def set_config(self, key: str, value: Any,
target: str = 'global',
target_id: str = None,
percentage: int = 100):
"""
设置配置
:param target: global / user / experiment / segment
"""
serialized = json.dumps(value)
if target == 'global':
self.redis.setex(f"config:global:{key}", 86400 * 30, serialized)
elif target == 'user':
self.redis.setex(f"config:user:{target_id}:{key}", 86400, serialized)
elif target == 'experiment':
self.redis.setex(f"config:exp:{target_id}:{key}", 86400, serialized)
elif target == 'segment':
self.redis.setex(f"config:segment:{target_id}:{key}", 86400, serialized)
# 清除本地缓存
self.local_cache.pop(key, None)
def grayscale_release(self, config_key: str, new_value: Any,
target_segments: List[str],
percentage: int = 10):
"""灰度发布配置"""
# 先在目标分群中灰度
for segment_id in target_segments:
self.set_config(
config_key,
new_value,
target='segment',
target_id=segment_id
)
# 记录灰度配置
grayscale_record = {
'key': config_key,
'old_value': self.get_config(config_key),
'new_value': new_value,
'target_segments': target_segments,
'percentage': percentage,
'started_at': datetime.now().isoformat()
}
self.redis.setex(
f"grayscale:{config_key}",
86400 * 7,
json.dumps(grayscale_record)
)
八、总结
本文系统阐述了平台整体能力与功能特性的设计与实现:
| 模块 | 核心功能 | 关键技术 |
|---|---|---|
| 用户分群 | 动态/静态分群、成员管理、实时判定 | 标签体系、规则引擎、缓存优化 |
| ABTest | 实验管理、变体分配、流量正交、统计检验 | 分层哈希、正交分配、T检验 |
| 运营位 | 内容管理、定向投放、多端联动、实时更新 | 配置化、缓存策略、多端适配 |
| 联运分流 | 合作方管理、动态权重、流量分配 | 加权随机、自动调权、一致性哈希 |
| 配置中心 | 配置管理、灰度发布、多级回退 | Redis存储、灰度策略、本地缓存 |
这五大能力共同构成了平台运营的完整闭环------分群定义"给谁看",ABTest验证"怎么投效果好",运营位解决"在哪投",联运分流处理"给谁导",配置中心支撑"怎么快速调整"。它们互相配合、数据互通,共同支撑起平台的精细化运营和快速迭代能力。