6

我有一些后端服务器位于两个不同的数据中心(在美国和欧洲)。这些服务器只是在CPM基础上投放广告。

除此之外,我还有大而肥的主MySQL服务器为广告商的广告活动的资金余额提供服务。同样,所有广告活动都是在基础上投放的CPM

在从任何后端提供的每一次展示中,我都必须根据展示价格减少广告活动的资金余额。

例如,每次展示的价格是 1 美分。后端 A 已投放 50 次展示,并将减少资金余额 50 美分。支持的 B 已投放 30 次展示,它将减少资金余额 30 美分。

所以,我看到的主要问题是:

  • 后端每秒提供大约 2-3K 的展示次数。因此,恕我直言,在 MySQL 中减少资金余额并不是一个好主意。

  • 后端位于美国和欧盟的数据中心。MySQL 主服务器位于美国。网络延迟可能是个问题 [EU backend] <-> [US master]

作为可能的解决方案,我看到:

  • 用作Cassandra分布式计数器存储。我会尽可能长时间地了解这个解决方案。

  • 通过后端保留部分资金。例如,后端 A 正在连接到 master 并试图保留 $1。由于 $1 保留并存储在本地后端(Redis例如本地),因此以光速递减它没有问题。我看到的主要问题是,如果后端从交付方案中被禁用(从平衡器“断开”),则将资金从后端返回到主服务器。无论如何,这似乎是一个非常好的解决方案,并且可以保留在当前的技术堆栈中。

  • 有什么建议么?

UPD:一个重要的补充。以高精度投放广告印象并不那么重要。我们可以提供比请求更多的展示次数,但绝不会更少。

4

5 回答 5

5

与其减少余额,不如保留每个后端报告的所有工作的日志,然后在需要时通过从活动帐户中减去所有报告工作的总和来计算余额?

表:

campaign (campaign_id, budget, ...)
impressions (campaign_id, backend_id, count, ...)

报告工作:

INSERT INTO impressions VALUES ($campaign_id, $backend_id, $served_impressions);

仅在必要时计算活动的余额:

SELECT campaign.budget - impressions.count * $impression_price AS balance
FROM campaign INNER JOIN impressions USING (campaign_id);
于 2014-01-27T17:01:43.083 回答
4

这可能是最经典的广告投放/展示次数统计问题。您基本上是在尝试平衡几个目标:

  1. 没有服务不足的广告库存,因此没有赚到尽可能多的钱。
  2. 不会过度投放广告库存,因此可以免费投放,因为您不能为自己的错误向客户收费。
  3. 不要过快地投放展示,因为通常客户希望广告在给定的日历时间段内投放,并且在凌晨 2 点到 3 点之间的一个小时内投放所有广告会使这些客户不满意并且对他们没有任何好处。

这很棘手,因为您不一定知道给定位置会有多少展示次数(因为它取决于流量),如果您使用 CPC 而不是 CPM,它会变得更加棘手,因为您会引入另一个不可知的变量点击率。

没有一个单一的“正确”模式,但通过我多年的咨询,我看到成功的是:

  • 将后端数据库视为您的权威存储。根据需要由客户对其进行分区,以支持您的可扩展性和容错目标(将可能的中断限制为一小部分客户)。数据库知道您有一个广告插入订单,例如在 7 天内有 1000 次展示。它会定期更新(几分钟到几小时)以反映剩余库存和一些基本统计信息,以在缓存丢失的情况下引导缓存,例如实际

  • 不要为广告服务器级别的资金余额而烦恼。仅处理展示次数、费率和目标。事后通过日志记录和离线处理将其结算为货币余额。

  • 从一个非常轻量且快速的缓存(靠近网络服务器)提供广告库存,该缓存缓存广告订单的剩余展示次数和目标投放速度,并计算实际投放速度。

  • 使用相关数据记录所有投放的展示次数。

  • 定期收集服务速度并将其推送回数据库。

  • 定期收集日志并计算实际服务库存并将其推送回数据库。(由于中断、DoSe、垃圾邮件等,您可能需要从日志中重新计算。)

于 2014-01-23T22:20:56.847 回答
3

在您的大而肥主 MySQL 服务器上创建一个服务,为广告商的广告活动的资金余额提供服务。

此服务必须实现一个 getCampaignFund(idcampaign, requestingServerId, currentLocalAccountBalanceAtTheRequestingServer) ,它将一个 creditLimit 返回给区域服务器。

想象一下信用卡机制。您的主服务器将对您的区域服务器进行一些限制。一旦此限制减少,阈值将触发此请求以获取新限制。但是为了获得新的信用额度,区域服务器必须告知它从之前的额度中使用了多少。

您的区域服务器可能会另外实现以下服务:

  1. currentLocalCampaignAccountBalance getCampaignAccountBalance(idcampaign):通知特定活动的当前使用情况,因此主服务器可能会在特定时间更新所有活动。
  2. addCampaign(idcampaign, initialBalance):注册一个新的活动,它是开始信用额度。
  3. supendCampaign(idcampaign):暂停对广告系列的展示。
  4. resumeCampaign(idcampaign):恢复对广告系列的展示。
  5. currentLocalCampaignAccountBalance finishCampaign(idcampaign):完成一个活动并返回当前本地帐户余额。
  6. currentLocalCampaignAccountBalance updateCampaignLimit(idcampaign, newCampaignLimit):更新限制(区域服务器之间的信用重新分配)。该服务将更新活动信用额度并返回之前获得的信用额度的账户余额。

服务很棒,所以你有一个松散耦合的架构。即使您的主服务器离线一段时间,您的区域服务器也会继续运行,直到它们没有完成信用额度。

于 2014-01-28T14:23:19.490 回答
2

这可能不是一个详细的规范答案,但我会尽可能提供我的想法[并且至少是部分]解决方案。我不得不在这里猜测一下,因为这个问题并没有说明已经采取了哪些措施来识别 mysql 瓶颈,恕我直言,这是开始的地方。我这么说是因为恕我直言,每秒 1-2k 事务并没有超出 mysql 的范围。我很容易通过以下技术的某种组合来支持这么高[甚至更高]的卷,这里没有特别的顺序,因为它取决于测量告诉我的瓶颈是什么:0-数据库重新设计;1-调整缓冲器;2-添加柱塞;3个固态硬盘;4-分片;5-如果在 5.5 或更低版本上,则升级到 mysql 5.6+。所以我会进行一些测量并根据测量结果的要求应用上述内容。希望这可以帮助。

于 2014-01-24T16:10:05.123 回答
1

我假设

  • 广告可能以至少数千个批次购买
  • 有多个不同批次的广告同时投放,但并非所有广告同时接近空
  • 如果您的基础架构出现故障,可以投放一些额外的广告。

所以,这就是我的做法。

BigFat 后端有这些方法

  • getCurrentBatches()这将提供可以使用一段时间的批次列表。每个批次都包含一个速率,其中包含每秒可以投放的广告数量。每批还包含一个serveMax;在再次与 BigFat 交谈之前可能会投放多少广告。
  • deductAndGetNextRateAndMax(batchId, adsServed)这将扣除自上次调用以来投放的广告数量,并返回一个新的费率(可能相同)和一个新的serveMax。

为每批设置一个费率的原因是,当一批资金开始用完时,它的服务将减少,直到它完全耗尽。

如果一个后端有一段时间没有连接到 BigFat,它将到达 serveMax,并且只提供来自其他批次的广告。

根据serveMax,后端可能有几秒、几分钟甚至几小时的报告周期。剩下数百万次展示的全新批次可以安全运行很长时间,然后再报告回来。

当 BigFat 收到调用时,deductAndGetNextRateAndMax它会扣除已投放的广告数量,然后返回总剩余展示次数的 75%,直至配置的最大值。这意味着在批次结束时,如果不重新填充,则批次清空后会有一些广告投放,但最好是批次实际耗尽而不是长时间几乎耗尽。

于 2014-01-29T07:43:26.483 回答