2012-06-01 82 views
0

我有一个拥有数百万用户的网站(实际上它还没有,但我们可以想象一下),并且我想计算一些统计信息,如“过去一小时内登录”。如何计算实时统计数据?

的问题类似于这里所描述的:http://highscalability.com/blog/2008/4/19/how-to-build-a-real-time-analytics-system.html

最简单的方法是做一个选择是这样的:

select count(distinct user_id) 
from logs 
where date>='20120601 1200' and date <='20120601 1300' 

(当然其他条件可以申请的统计资料,例如登录每个国家) 当然,这将是非常缓慢,主要是如果它有数百万(甚至数千)的行,我想查询这每次页面显示。

你会如何总结数据?什么应该去(mem)缓存?

编辑:我正在寻找一种方法来取消规格化数据,或保持缓存最新。例如,每次有人登录时,我都可以增加内存中的变量,但这有助于了解登录的总数,而不是“最近一小时登录”。希望现在更清楚。

+1

你有这个标签为.net - 这是否意味着你在IIS托管?如果是这样的话,你可能想看看微软的AppFabric框架 - 它为你提供了一些预先构建的监控工具。 –

+0

@ 500-InternalServerError酷的名称和AppFabric – Paparazzi

回答

0

我已经结束了使用Esper/NEsper。还有Uri的建议在哪里有用。

Esper允许我在计算数据时获得实时统计数据。

1

如果你没有一个数据库然后没关系。我没有成千上万的用户,但我有一个桌面,拥有一百万行的登录年,并且在亚秒内拥有简单的统计信息。一百万行对于数据库来说并不那么重要。你不能让日期成为PK,因为你可以有重复的日期。为了最小化碎片和插入速度,使日期成为一个集群化的非唯一索引asc,这就是数据如何进入。不知道你是否有一个数据库,但在MSSQL中可以。索引user_id是要测试的东西。这样做会减慢插入速度,因为这是一个将会分段的索引。如果你寻找一个相当紧张的时间跨度表扫描可能是好的。

为什么独特的user_id而不是登录是登录。

有一个属性只能每隔x秒运行一次查询。即使每秒都报告缓存的答案。如果在200秒内或者200页的时间内击中了这个属性,那么你肯定不需要200次查询。如果统计信息在过去一小时内仍然是一个有效统计信息的陈旧信息。

+0

的不错提示为计划的统计计算+1。许多人甚至不会停下来认为在请求执行时调用者不必计算。在繁忙的系统中,甚至5或10秒钟缓存这样的查询是巨大的性能优势。 – Chris

2

IMO更正确的方法是实现一个连续的计算,将相关计数器保存在内存中。每次将用户添加到系统中时,您都可以启动一个可以多种方式处理的事件,并在上一小时,最后一天甚至总用户计数器中进行更新。有一些很棒的框架可以完成这种处理。 Twitter Storm是其中之一,另一个是GigaSpaces XAP(免责声明 - 我为GigaSpaces工作),特别是this tutorial,还有Apache S4GridGain

0

如果您只是在运行日志,那么您可能需要查看诸如Splunk之类的东西。

一般来说,如果你想要这个内存中和快速(实时),你可以创建一个分布式缓存的登录数据与驱逐后,例如。 24小时,然后你可以查询该缓存,例如在过去一小时内登录。

假设登录记录看起来类似:

public class Login implements Serializable { 
    public Login(String userId, long loginTime) {..} 
    public String getUserId() {..} 
    public long getLoginTime() {..} 
    public long getLastSeenTime() {..} 
    public void setLastSeenTime(long logoutTime) {..} 
    public long getLogoutTime() {..} 
    public void setLogoutTime(long logoutTime) {..} 
    String userId; 
    long loginTime; 
    long lastSeenTime; 
    long logoutTime; 
} 

为了支持驱逐24小时后,只需在缓存

<expiry-delay>24h</expiry-delay> 

当前查询所有用户配置失效(TTL)登录:

long oneHourAgo = System.currentTimeMillis() - 60*60*1000; 
Filter query = QueryHelper.createFilter("loginTime > " + oneHourAgo 
             + " and logoutTime = 0"); 
Set idsLoggedIn = cache.keySet(query); 

要查询登录和/或活动用户数过去一小时:

long oneHourAgo = System.currentTimeMillis() - 60*60*1000; 
Filter query = QueryHelper.createFilter("loginTime > " + oneHourAgo 
             + " or lastSeenTime > " + oneHourAgo); 
int numActive = cache.keySet(query).size(); 

(有关查询的详细信息,请参阅http://docs.oracle.com/cd/E15357_01/coh.360/e15723/api_cq.htm。所有这些示例均来自Oracle Coherence。)

为了充分披露,我在Oracle工作。本文所表达的意见和观点属于我自己的观点,并不一定反映我的雇主的意见或看法。