浏览量的简单设计

前往原站点查看

2022-10-21 16:24:50

    哈喽,又是一天早起的日子,今天就写写昨天实现了的浏览量逻辑设计,顺带一些其它的小知识总结,

设计思路

    基本需求是当用户进入到某一篇博客的时候,该博客的浏览量+1,并且同一个用户同一天访问的博客不会再次增加1,即一天一个用户只会绑定一次某个博客。

    基于这个需求,最开始设计的时候就简单的对getBlogById进行了一个扩展,就是在获取博客之前先对博客的visit进行自增,之后再返回博客给前端。此外还支持事务操作,遇到异常就进行回滚。然而事实是纯粹的这样操作,无法甄别是否是同一个用户拼命刷浏览量,无法表达出一篇文章的真实价值。

    所以就想着也许可以通过用户的ip进行处理,虽然说同一个网络下的内网该ip都一样,不过基本可以满足需求。那么数据使用什么来存储呢?那当然是redis了,将所有用户维系到一个redis的一个set中即可。当然了,对于不同博客一个用户当然是可以分别增加浏览量的,所以不能只依据ip来进行反馈,所以我简单的设计了一个规则来区分:

ip#blog:id

    首先第一段是ip地址,后面是#号用来分隔,接着跟上目标大类,以及具体的文章id。每次判断set中是否存在来决定是否为其自增,不过不管怎样都要返回博客列表就是了。对于该set集合,每天0点的时候也需要自动清空一下。

实现代码

    首先是原始的博客获取service代码:

    @Override
    public RetResult<Blog> getBlogById(Integer id) {
        return RetResult.success(blogDao.getBlogById(id));
    }

    接着我们对该方法重载扩充功能实现,先尝试从库中尝试查找到该串,如果没找到或者未定义set,那么就添加该串并且调用增加访客量的逻辑:

@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@Override
public RetResult<Blog> getBlogById(Integer id, String addr) {
    String targetSer = addr + "#blog:" + id;
    String vsStr = RedisConst.VISIT_SET;
    SetOperations<String,String> ops = redisTemplate.opsForSet();
    Boolean res = ops.isMember(vsStr, targetSer);
    if (res == null || !res){
        // 该用户今日未访问该博客, 新增访问量,并且将访问记录记入redis的visitSet中
        ops.add(vsStr, targetSer);
        blogDao.increaseVisit(id);
        // 如果已经访问,不增加新的访问。
    }
    return getBlogById(id);
}

    对于定时任务,只要简单的调用一下delete即可:

    @Scheduled(cron = "0 0 0 * * ?")
    public void visitSetClear(){
        Boolean delete = redisTemplate.delete(RedisConst.VISIT_SET);
        if (delete != null)
            log.info("redis:{} clear - {}", RedisConst.VISIT_SET, delete?"clear":"non 2 clear");
    }

数据安全

    现在的redis服务数据就有了一定的重要性,那么肯定也想到对redis服务进行备份,可以采用主从服务器的策略来实现。

    首先另外一台服务器做好如下的配置:

port 6379
protected-mode yes
daemonize yes
dir /home/dai/server/redis
dbfilename dump_6379.rdb
logfile /home/dai/server/redis/redis.log
pidfile /home/dai/server/redis/redis.pid
requirepass xxxxxx
replicaof <ip> <port>
masterauth xxxxxx

    这样这台redis服务器就会自动获得主服务器的数据了。

其它发现

    这段时间,也发现了一些其它结论:

server.servlet.encoding.force=true


上一篇:分布式项目搭建的一些小结
下一篇:服务器子用户创建运用