从众多后端减少存储在主服务器上的资金余额? (分发计数器,嗯?)

时间:2014-01-21 05:45:17

标签: mysql architecture counter distributed adserver

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

除此之外,我还有一个很大的&胖主MySQL服务器服务广告客户的广告系列的余额。同样,所有广告系列都是以CPM为基础提供的。

在每个后端投放的每次展示中,我都必须根据展示价格减少广告系列的余额。

例如,每次展示的价格为1美分。后端A已经实现了50次展示,并将减少50美分的资金余额。支持B已经提供了30次印象,它将使货币余额减少30美分。

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

  • 后端每秒提供2-3K的展示次数。因此,在MySQL中减少货币余额并不是一个好主意。

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

我认为可能的解决方案是:

  • 使用Cassandra作为分布式计数器存储。我会尽可能地意识到这个解决方案。

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

  • 有什么建议吗?

UPD:一个重要的补充。提供高精度的广告展示并不是那么重要。我们可以提供超出要求的展示次数,但绝不会少。

5 个答案:

答案 0 :(得分: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);

答案 1 :(得分:4)

这可能是最经典的广告投放/印象计数问题。你基本上试图平衡一些目标:

  1. 没有广告资源不足,因此没有赚到尽可能多的钱。
  2. 不会过度投放广告资源,因此您可以免费投放,因为您无法向客户收取错误费用。
  3. 不能过快地提供展示次数,因为通常客户希望广告在指定的日历时段内运行,并且在凌晨2-3点之间的一小时内为所有客户提供服务会让这些客户感到不快,并且不会对他们产生任何好处。
  4. 这很棘手,因为您不一定知道给定广告点可用的展示次数(因为它取决于流量),如果您执行CPC而非CPM,则会变得更加棘手,因为您会引入另一个点击率不可知的变量。

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

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

    • 不要打扰广告服务器级别的资金余额。仅处理展示次数,费率和目标。事后通过记录和离线处理将其结算到货币余额。

    • 从非常轻量级的快速缓存(靠近网络服务器)投放广告资源,缓存展示订单的展示次数和目标服务速度,并计算实际服务速度。

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

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

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

答案 2 :(得分:3)

在您的大人物上创建一项服务胖主MySQL服务器为广告客户的广告系列提供资金余额。

此服务必须实现将creditLimit返回到区域服务器的getCampaignFund(idcampaign,requestedServerId,currentLocalAccountBalanceAtTheRequestingServer)。

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

您的区域服务器可能会另外实施这些服务:

  1. currentLocalCampaignAccountBalance getCampaignAccountBalance(idcampaign):告知特定广告系列的当前使用情况,以便主服务器可以在特定时间更新所有广告系列。
  2. addCampaign(idcampaign,initialBalance):注册新的广告系列 并且它开始信用额度。
  3. supendCampaign(idcampaign):暂停展示次数 广告活动。
  4. resumeCampaign(idcampaign):恢复对广告系列的展示。
  5. currentLocalCampaignAccountBalance finishCampaign(idcampaign):to 完成广告系列并返回当前的本地帐户余额。
  6. currentLocalCampaignAccountBalance updateCampaignLimit(idcampaign,newCampaignLimit):更新限制 (区域服务器之间的信用调用)。这项服务会 更新广告系列信用额度并返回帐户余额 获得之前的信用额度。
  7. 服务很棒,所以你有一个松散耦合的架构。即使您的主服务器脱机一段时间,您的区域服务器也会一直运行,直到它们没有完成信用额度。

答案 3 :(得分:2)

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

答案 4 :(得分:1)

我假设

  • 广告可能至少分批购买
  • 同时发送来自多个不同批次的广告,而不是所有广告同时接近空白
  • 如果您的基础架构已关闭,可以投放一些额外的广告。

所以,我就是这样做的。

BigFat后端有这些方法

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

每个批次的费率的原因是,当一个批次开始耗尽资金时,它将减少供应,直到它完全耗尽。

如果一个后端暂时无法连接到BigFat,它将到达serveMax并仅提供其他批次的广告。

后端可能有一个秒,分钟甚至小时的报告周期,具体取决于serveMax。在报告之前,一个拥有数百万印象的全新批次可以安全运行很长一段时间。

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