You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现按访问量占比分配的多设计A/B测试流量重定向咨询

一、核心疑问解答

1. 「按总访问量而非用户数占比分配」的具体含义

按总访问量占比分配的统计维度是单次访问请求,而非独立用户/独立设备:

  • 例如总访问量为1000次时,严格按照配置比例分配500次到Design A、250次到Design B、250次到Design C
  • 即使用户重复访问,每次访问都会被计入总访问量统计,不会因为用户之前看过某版本就固定分配,和基于用户标识固定版本的用户维度分配逻辑完全不同,更适合需要按流量比例精准切分的场景。

2. 所需数据库表结构设计

我们设计两张核心表,完全支持多活动、多变体的扩展需求:

ab_test_campaigns 活动主表

字段名类型说明
idint(11) 主键活动唯一ID
campaign_namevarchar(100)活动名称
is_activetinyint(1)是否启用 0=停用 1=启用
entry_urlvarchar(255)活动入口访问地址
total_visitsbigint(20)活动累计总访问量
created_atdatetime创建时间
updated_atdatetime更新时间

ab_test_variants 变体配置表

字段名类型说明
idint(11) 主键变体唯一ID
campaign_idint(11) 外键关联活动ID
variant_namevarchar(50)变体名称 如Design A
redirect_urlvarchar(255)变体跳转目标地址
weightint(3)分配占比 单位% 总和为100
current_visitsbigint(20)该变体累计访问量
is_enabledtinyint(1)是否启用 0=停用 1=启用

上述结构已经支持单个活动无限新增变体,只需要调整各变体的weight占比即可,无需额外冗余字段。

3. 高效实现方案

为了避免每次请求都查库、锁表的性能问题,采用以下逻辑:

  • 先从缓存读取当前活动的总访问量、各变体占比和访问量配置,不用每次请求查库
  • 计算当前总访问量模100的余数,匹配余数落在哪个变体的占比区间,算法复杂度极低
  • 异步更新总访问量和对应变体的访问量到数据库,不阻塞用户重定向
  • 缓存1分钟自动刷新一次配置,并发场景下的误差在可接受范围内,完全满足业务需求

二、PHP代码实现示例

<?php
// 数据库连接 可替换为项目自身的DB类
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'your_db_password');

// 匹配当前请求的入口路径
$currentUrl = $_SERVER['REQUEST_URI'];
$cacheKey = 'ab_test_active_campaigns';

// 先读缓存 这里用Redis示例 可替换为项目自身缓存组件
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$campaigns = $redis->get($cacheKey);

if (!$campaigns) {
    // 缓存过期 从DB读取所有启用的活动和变体
    $stmt = $pdo->query("SELECT c.*, v.id as variant_id, v.redirect_url, v.weight 
                        FROM ab_test_campaigns c 
                        LEFT JOIN ab_test_variants v ON c.id = v.campaign_id 
                        WHERE c.is_active = 1 AND v.is_enabled = 1");
    $rawData = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    // 整理数据结构
    $campaigns = [];
    foreach ($rawData as $item) {
        if (!isset($campaigns[$item['entry_url']])) {
            $campaigns[$item['entry_url']] = [
                'id' => $item['id'],
                'total_visits' => $item['total_visits'],
                'variants' => []
            ];
        }
        $campaigns[$item['entry_url']]['variants'][] = [
            'id' => $item['variant_id'],
            'redirect_url' => $item['redirect_url'],
            'weight' => $item['weight']
        ];
    }
    // 写入缓存 有效期60秒
    $redis->setex($cacheKey, 60, json_encode($campaigns));
} else {
    $campaigns = json_decode($campaigns, true);
}

// 匹配当前请求是否属于A/B测试活动
if (isset($campaigns[$currentUrl])) {
    $campaign = $campaigns[$currentUrl];
    $totalVisits = $campaign['total_visits'];
    $remainder = $totalVisits % 100;
    
    // 匹配变体区间
    $currentRange = 0;
    $targetVariant = null;
    foreach ($campaign['variants'] as $variant) {
        $currentRange += $variant['weight'];
        if ($remainder < $currentRange) {
            $targetVariant = $variant;
            break;
        }
    }
    
    if ($targetVariant) {
        // 生产环境建议用异步任务/消息队列更新访问量,避免阻塞重定向
        $pdo->exec("UPDATE ab_test_campaigns SET total_visits = total_visits + 1 WHERE id = {$campaign['id']}");
        $pdo->exec("UPDATE ab_test_variants SET current_visits = current_visits + 1 WHERE id = {$targetVariant['id']}");
        
        // 执行重定向
        header("Location: {$targetVariant['redirect_url']}");
        exit;
    }
}

// 没有匹配到活动 走原有业务逻辑

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 20:15:01