0


Redis实现朋友圈,微博等Feed流功能,实现Feed流微服务(业务场景、实现思路和环境搭建)

文章目录

业务场景

在互联网领域,尤其现在的移动互联网时代,Feed流产品是非常常见的,比如我们每天都会用到的朋友圈,微博,就是一种非常典型的Feed流产品,还有图片分享网站Pinterest,花瓣网等又是另一种形式的Feed流产品。除此之外,很多App的都会有一个模块,要么叫动态,要么叫消息广场,这些也是Feed流产品,可以说,Feed流产品是遍布天下所有的App中。
在这里插入图片描述

Feed流相关概念

我们在讲如何设计Feed流系统之前,先来看一下Feed流中的一些概念:

  • Feed:Feed流中的每一条状态或者消息都是Feed,比如朋友圈中的一个状态就是一个Feed,微博中的一条微博就是一个Feed。
  • Feed流:持续更新并呈现给用户内容的信息流。每个人的朋友圈,微博关注页等等都是一个Feed流。
  • Timeline:Timeline其实是一种Feed流的类型,微博,朋友圈都是Timeline类型的Feed流,但是由于Timeline类型出现最早,使用最广泛,最为人熟知,有时候也用Timeline来表示Feed流。
  • 关注页Timeline:展示其他人Feed消息的页面,比如朋友圈,微博的首页等。
  • 个人页Timeline:展示自己发送过的Feed消息的页面,比如微信中的相册,微博的个人页等。
  • 总结来说,Feed是将用户主动订阅的若干消息源组合在一起形成内容聚合器,帮助用户持续地获取最新的订阅源内容。Feed流即持续更新并呈现给用户内容的信息流。

Feed流特征

Feed流系统有一些非常典型的特点,比如:

  • 多账号内容流:Feed流系统中肯定会存在成千上万的账号,账号之间可以关注,取关,加好友和拉黑等操作。只要满足这一条,那么就可以当做Feed流系统来设计。
  • 非稳定的账号关系:由于存在关注,取关等操作,所以系统中的用户之间的关系就会一直在变化,是一种非稳定的状态。
  • 读写比例100:1:读写严重不平衡,读多写少,一般读写比例在10:1,甚至100:1以上。
  • 消息必达性要求高:比如发送了一条朋友圈后,结果部分朋友看到了,部分朋友没看到,这就很有问题,如果偏偏女朋友没看到,那么可能会产生很严重的感情矛盾,后果很严重。

Feed流分类

Feed流的分类有很多种,但最常见的分类有两种:

  • Timeline:按发布的时间顺序排序,先发布的先看到,后发布的排列在最顶端,类似于微信朋友圈,微博等。这也是一种最常见的形式。产品如果选择Timeline类型,那么就是认为Feed流中的Feed不多,但是每个Feed都很重要,都需要用户看到。
  • Rank:按某个非时间的因子排序,一般是按照用户的喜好度排序,用户最喜欢的排在最前面,次喜欢的排在后面。这种一般假定用户可能看到的Feed非常多,而用户花费在这里的时间有限,那么就为用户选择出用户最想看的Top N结果,场景的应用场景有图片分享、新闻推荐类、商品推荐等。

实现思路

解决Feed流最核心的两个问题:一个是存储,另一个是推送
① 存储
因为该项目中Feed比较简单,就类比于空间说说,因此可以使用MySQL关系型数据库存储,如果对于数据结构比较复杂的Feed流就要使用NoSQL数据库,这样存储更方便与高效,比如MongoDB或者HBase。
② 推送,在推送方案里面的,有三种方案,分别是:

  • 拉方案:也称为读扩散,用户主动去拉取关注人的Feed内容
  • 推方案:也成为写扩散,当用户添加Feed时,会自动将Feed通知给关注的人(优选)。使用Redis Sorted Sets(方便按时间排序Timeline)维护粉丝的Feed集合,当博主添加Feed时,主动将内容推送到粉丝的Feed集合中,这样用户可以很方便快速从集合中读取
  • 推拉结合:比如微博,大部分用户的账号关系都是几百个,但是有个别用户是1000万以上。

环境搭建

数据库表结构

CREATETABLE`t_feeds`(`id`INT(11)NOTNULLAUTO_INCREMENT,`content`VARCHAR(500)CHARACTERSET utf8mb4 COLLATE utf8mb4_general_ci NULLDEFAULTNULLCOMMENT'内容',`fk_user_id`INT(11)NULLDEFAULTNULL,`praise_amount`INT(11)NULLDEFAULTNULLCOMMENT'点赞数量',`comment_amount`INT(11)NULLDEFAULTNULLCOMMENT'评论数量',`fk_restaurant_id`INT(11)NULLDEFAULTNULLCOMMENT'餐厅外键',`create_date`datetimeNULLDEFAULTNULL,`update_date`datetimeNULLDEFAULTNULL,`is_valid`TINYINT(1)NULLDEFAULTNULL,PRIMARYKEY(`id`))ENGINE=INNODBDEFAULTCHARACTERSET= utf8mb4 COLLATE= utf8mb4_general_ci AUTO_INCREMENT=14 ROW_FORMAT = COMPACT;

新建Feeds功能微服务ms-feeds

pom依赖:

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>redis-seckill</artifactId><groupId>com.zjq</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ms-feeds</artifactId><dependencies><!-- eureka client --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- spring web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- spring data redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- mybatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!-- commons 公共项目 --><dependency><groupId>com.zjq</groupId><artifactId>commons</artifactId><version>1.0-SNAPSHOT</version></dependency><!-- swagger --><dependency><groupId>com.battcn</groupId><artifactId>swagger-spring-boot-starter</artifactId></dependency></dependencies></project>

SpringBoot配置文件:

server:port:7005# 端口spring:application:name: ms-feeds # 应用名# 数据库datasource:driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1:3306/seckill?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false# Redisredis:port:6379host: localhost
    timeout:3000password:123456database:2# Swaggerswagger:base-package: com.zjq.feeds
    title: Feed功能微服务API接口文档

# 配置 Eureka Server 注册中心eureka:instance:prefer-ip-address:trueinstance-id: ${spring.cloud.client.ip-address}:${server.port}client:service-url:defaultZone: http://localhost:7000/eureka/

service:name:ms-oauth-server: http://ms-oauth2-server/
    ms-users-server: http://ms-users/

mybatis:configuration:map-underscore-to-camel-case:true# 开启驼峰映射logging:pattern:console:'%d{HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n'

启动类:

packagecom.zjq.feeds;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/**
 * Feeds功能微服务
 * @author zjq
 */@MapperScan("com.zjq.feeds.mapper")@SpringBootApplicationpublicclassFeedsApplication{publicstaticvoidmain(String[] args){SpringApplication.run(FeedsApplication.class);}}

配置类 RedisTemplateConfiguration

/**
 * RedisTemplate配置类
 *
 * @author zjq
 */@ConfigurationpublicclassRedisTemplateConfiguration{/**
     * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
     *
     * @param redisConnectionFactory
     * @return
     */@BeanpublicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){RedisTemplate<Object,Object> redisTemplate =newRedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =newJackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper =newObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置key和value的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(newStringRedisSerializer());

        redisTemplate.setHashKeySerializer(newStringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();return redisTemplate;}}

REST配置类 RestTemplateConfiguration

/**
 * RestTemplate 配置类
 * @author zjq
 */@ConfigurationpublicclassRestTemplateConfiguration{@LoadBalanced@BeanpublicRestTemplaterestTemplate(){RestTemplate restTemplate =newRestTemplate();MappingJackson2HttpMessageConverter converter =newMappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN));
        restTemplate.getMessageConverters().add(converter);return restTemplate;}}

Feeds 实体类

/**
 * Feed信息类
 * @author zjq
 */@Getter@Setter@ApiModel(description ="Feed信息类")publicclassFeedsextendsBaseModel{@ApiModelProperty("内容")privateString content;@ApiModelProperty("用户id")privateInteger fkUserId;@ApiModelProperty("点赞")privateint praiseAmount;@ApiModelProperty("评论")privateint commentAmount;@ApiModelProperty("关联的餐厅")privateInteger fkRestaurantId;}

FeedsVO 响应类

在这里插入图片描述

后续博文我会讲解如何实现添加 Feed 信息、删除 Feed 信息、关注/取关时处理用户相关Feed、分页获取关注的 Feed 数据等功能。

本文内容到此结束了,
如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问💬欢迎各位指出。
主页:共饮一杯无的博客汇总👨‍💻

保持热爱,奔赴下一场山海。🏃🏃🏃


本文转载自: https://blog.csdn.net/qq_35427589/article/details/128325747
版权归原作者 共饮一杯无 所有, 如有侵权,请联系我们删除。

“Redis实现朋友圈,微博等Feed流功能,实现Feed流微服务(业务场景、实现思路和环境搭建)”的评论:

还没有评论