看到比较早的一篇用redis bit来实现用户统计的文章,照着用C#实现了一下,记录一下过程。

关于bit操作的解释,请参考上面文章。

说明

Redis里关于bit操作有下面命令:

  • BITCOUNT key [start end], Count set bits in a string
  • BITOP operation destkey key [key …], Perform bitwise operations between strings
  • BITPOS key bit [start] [end], Find first bit set or clear in a string
  • GETBIT key offset, Returns the bit value at offset in the string value stored at key
  • SETBIT key offset value, Sets or clears the bit at offset in the string value stored at key

这里主要依赖SETBIT/BITOP/BITCOUNT几个命令来操作。

代码实现

直接上代码:

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        var random = new Random();
        LogLogin(random.Next(1000, 999999)); // fake customer number
        LogLogin(random.Next(1000, 999999)); // fake customer number
        LogLogin(random.Next(1000, 999999));
        Console.WriteLine("we totally have {0} actives users today.", getTodayActiveUserCount());
        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        Console.ReadKey();
    }

    public static void LogLogin(int customerNumber)
    {
        using (var client = new PooledRedisClientManager("192.168.1.181"))
        using (var redis = (RedisNativeClient)client.GetClient())
        {
            redis.SetBit(string.Format("user-logon-activities:{0:yyyy-MM-dd}", DateTime.Now), customerNumber, 1);
        }
    }

    public static int getTodayActiveUserCount()
    {
        using (var client = new PooledRedisClientManager("192.168.1.181"))
        using (var redis = (RedisNativeClient)client.GetClient())
        {
            return (int)redis.BitCount(string.Format("user-logon-activities:{0:yyyy-MM-dd}", DateTime.Now));
        }
    }
}

这里,代码使用了servicestack.redis类库,请通过nuget添加引用。

在redis里定义了一组以格式为user-logon-activities:{yyyy-MM-dd}定义的key,如:'user-logon-activities:2016-01-26', 在id为1234的customer登陆时,会执行redis命令`setbit ‘user-logon-activities:2016-01-26’ 1234 1`来标示这个customer在2016-01-26登陆过。

在统计具体2016-01-26日多少个客人登陆过,可以简单使用bitcount 'user-logon-activities:2016-01-26'即可。

同样,可以通过redis的bitop来进行位操作来统计来对多日的数据进行统计,如:

  • 连续两天内总的登陆用户数:

    bitop or 'user-logon-activities:2016-01:25-26' 'user-logon-activities:2016-01-26' 'user-logon-activities:2016-01-25'
    bitcount 'user-logon-activities:2016-01:25-26'
  • 连续两天内都登陆过的用户数:

    bitop and 'user-logon-activities:2016-01:25-26' 'user-logon-activities:2016-01-26' 'user-logon-activities:2016-01-25'
    bitcount 'user-logon-activities:2016-01:25-26'

PS: ServiceStack.Redis 的RedisNativeClient暂时不支持bitop操作,不过可以通过在后端通过redis command预处理数据的方式来操作。