首页 > Redis > 使用Redis快速统计今日签到用户数,用户是否签到,活跃用户数统计等
2015
10-14

使用Redis快速统计今日签到用户数,用户是否签到,活跃用户数统计等

    Redis:关于它就不多做介绍了.

    为什么使用Redis,原因如下:

        原因1: 由于在开发签到功能时,每一个用户的每天都能签到一次,并在表中记录签到用户,为了防止用户每天多次签到,需要判断用户今日是否签到,这时就会根据用户和日期来查询签到记录。开发完成后,测试是没有问题的,但没有考虑到以后数据量大了的情况。APP上线后用户数增长很快,在一个月内达到几万,也就是说每天的签到用户数,就有几万条数据,这样会导致查询轻慢。还会导致查询线程超时,直接导致线程池中的线程一直处于等待状态,直接搞死服务器。

        原因2:在开发时,签到用户数过多,也会直接搞死服务器,所以运维提出,硬件服务器不可能再加了,因为现在已有4台服务器,叫我们开发人员用技术解决,提出使用队列来排队签到,还为满足以后的业务需求,只有前5000个用户能签到,其它用户明日再来.给予连续签到成功的用户更多奖励。

       原因3:缓存的替换,以前是使用的Ehcache,现在技术提出使用redis来做,具体原因可能是性能考虑,缓存丢失问题.

      

      在学习redis时,无意看到网上关于使用Redis来统计活跃用户的博文,参考了之后,确实发现是一个好的方法.

      在使用效率上肯定要比数据库查询快很多.

     

      可使用redis实现的案例如下:

            1)验证用户今日是否签到

            2)查询用户本月签到成功次数

            3)活跃用户统计

            4)查询今日签到用户数(用来解决前5000个签到)

      具体实现如下:

      

package com.coarsky.spu.redis;

import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.Date;

import redis.clients.jedis.Jedis;

/**
 * 测试使用Redis来
 * 1.统计当前签到用户数(解决只能前5000个用户签到成功)
 * 2.验证指定用户是否签到
 * 3.活跃用户数统计
 * 4.查询本月签到用户数
 * 5.查询指定日期内的用户签到次数
 * @author yangxixi
 *
 */
public class RedisBitSetTest {
	static Jedis jedis = new Jedis("localhost");
	
	public static void main(String[] args) {
		//放入数据
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		String date = df.format(new Date());
		String loginAction = "login" ;
		String signinAction = "signin";
		long user_id = 134080953 ; //此处使用的是手机号码
		long user_id2 = 134080932 ; //此处使用的是手机号码
		jedis.setbit(loginAction+":"+date, user_id, true); //保存用户登录
		jedis.setbit(signinAction+":"+date, user_id, true); //保存用户签到
		jedis.setbit(loginAction+":"+date, user_id2, true); //保存用户登录
		jedis.setbit(signinAction+":"+date, user_id2, true); //保存用户签到
		
		System.out.println("验证用户"+user_id+"是否"+signinAction+":"+isAction(loginAction, date, user_id));
		System.out.println("今天签到用户数:"+uniqueCount(signinAction, date));
	}
	
	/**
	 * 查询用户今日是否签到或者做活动 
	 * 这样大大减少数据库查询的时间和效率
	 * @param action  要做的事件:签到,登录,做活动等等
	 * @param date    日期
	 * @param offset  用户(指对应key这个用户是否为1)
	 * @return
	 */
	public static boolean isAction(String action,String date,long offset){
		String key = action + ":" + date ;
		return jedis.getbit(key, offset);
	}
	
	/**
	 * 查询指定用户时间内的操作
	 * 例如:查询本月签到次数
	 * @param action
	 * @param offset
	 * @param date
	 * @return
	 */
	public static int queryAction(String action,long offset,String...dates){
		int sum = 0 ;
		for (String date : dates) {
			String key = action + ":" + date ;
			boolean value = jedis.getbit(key, offset);
			if (value)
				sum++ ;
		}
		return sum;
	}
	
	/**
	 * 查询今日签到用户数或者活跃用户数
	 * @param action 要做的事件:签到,登录,做活动等等
	 * @param date   指定日期或者今日
	 * @return 次数
	 */
	public static int uniqueCount(String action,String date){
		String key = action + ":" + date ;
		byte[] bytes = jedis.get(key.getBytes());
		BitSet bitSet = byteArray2BitSet(bytes);
		return bitSet.cardinality();
	}
	
	/**
	 * 查询指定日期的用户签到数
	 * @param action 要做的事件:签到,登录,做活动等等
	 * @param dates 指定日期
	 * @return 次数
	 */
	public static int uniqueCount(String action,String...dates){
		BitSet bitSet = new BitSet();
		for(String date:dates){
			String key = action + ":" + date ;
			BitSet bitSet2 = byteArray2BitSet(jedis.get(key.getBytes()));
			bitSet.or(bitSet2);
		}
		return bitSet.cardinality();
	}
	
	/**
	 * 将字节数组转换为位
	 * @param bytes
	 * @return BitSet
	 */
	public static BitSet byteArray2BitSet(byte[] bytes) {
		BitSet bitSet = new BitSet(bytes.length * 8);
		int index = 0;
		for (int i = 0; i < bytes.length; i++) {
			for (int j = 7; j >= 0; j--) {
				bitSet.set(index++, (bytes[i] & (1 << j)) >> j == 1 ? true
						: false);
			}
		}
		return bitSet;
	}
}

大家也可以根据业务需求做相应的扩展.

最后编辑:
作者:noname
noname
这个作者貌似有点懒,什么都没有留下。

留下一个回复

你的email不会被公开。