广告投放系统


CommonResponseAdvice

将字段进行包装进行填充,规范化API返回格式:通过统一响应,可以定义API的返回格式,包括状态码、消息、数据等内容,使得不同的接口返回风格一致,提高了接口的可预测性和可读性。

JpaRepository的继承过程

关于JpaRepository的继承过程

Feign和Hystrix

关于Feign和Hystrix的整合,可以参考以下文章:

如何理解服务调用,阶段器和负载均衡

RESTful

有关RESTful的介绍,可以参考以下文章:

浅谈restful

注解

  • @Transactional,声明一个方法需要进行事务管理,并指定事务的隔离级别、传播行为和超时时间等属性。

思想

  • 接口可以继承自什么?
    接口可以继承自接口,但不能继承自类。这意味着一个接口可以通过使用关键字 extends 来扩展(继承)另一个接口。通过接口继承,子接口可以获得父接口中声明的方法签名,但不包括方法的实现。

binlog

binlog原理

  1. 主库将数据库中的数据的变化写入到binlog日志文件中
    2 从库通过连接主库
  2. 从库会创建一个i/o线程,用于读取主库的binlog日志文件,并将数据的变化同步到自己的数据库中。
  3. 主库会创建一个binlog dump线程,用于将binlog日志文件发送给从库的i/o线程。
  4. 从库的i/o线程接收到binlog日志文件后,会写到relaylog日志文件中。
  5. 从库的SQL线程会读取relaylog日志文件中的数据变化,并将其应用到自己的数据库中。

如何避免主从延迟

如果我们无法忍受主从同步延迟我们可以又两种方法进行解决

  • 强制将读请求路由到主库处理
  • 延迟读取
    如果主从同步延迟是0.5s,我们就1s后进行读取数据

什么情况下会出现主从延迟,如何尽量减少延迟

其中又两个io我们可以想到,明显是由于两个io的速度不一致导致的

  • 其中第一个io是从库接受binlog的速度明显跟不上主库写入binlog的时间
  • 第二个是从库的sql线程执行relaylog的速度明显跟不上从库接受binlog的速度

我们可以考虑从优化上述的机器性能进行解决问题

分库分表

什么是分库

分库就是将数据库中的数据分散到不同的数据库中,可以垂直分库,也可以水平分库
垂直分库就是将不同的表分散到不同的数据库中,水平分库就是将不同的数据分散到不同的表中
举个例子

  • 垂直分库
    将不同的业务逻辑进行分库
  • 水平分库
    将表的主键按照一定的原则进行划分

什么是分表

分表就是将一张表中的数据分散到不同的表中,可以垂直分表,也可以水平分表
垂直分表就是将不同的字段分散到不同的表中,水平分表就是将不同的数据分散到不同的表中
举个例子

  • 垂直分表
    就是根据表的属性进行划分
  • 水平分表
    就是将按照主键的id进行划分

消息队列

消息队列有什么用

一共有三个作用

  • 解耦
  • 异步处理
  • 削峰填谷
    其中我的项目用到了两种作用
  • 其中的第一个作用是进行解耦,binlog的其中一个缺陷是多服务器时会造成数据库压力大
    而我们知道消息队列使用的时发布-订阅模式进行工作,这时我们新增从数据库我们可以进行直接订阅,从而实现网站业务的可扩展性设计
  • 其中的第二个作用是进行异步处理,在广告投放系统中,我们使用消息队列进行广告投放的异步处理,从而实现广告投放的效率

讲一下什么时JMS和AMQP

  • JMS(Java Message Service)
    JMS是Java平台中关于面向消息中间件的API,它定义了用于创建、发送、接收消息的Java应用程序接口,用于在JVM的两种或多个应用程序之间,进行异步通信。
  • AMQP(Advanced Message Queuing Protocol)
    AMQP是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。

RPC和消息队列的区别

  • 从用途上来看
    RPC是远程过程调用,用于服务之间的调用,而消息队列是用于服务与服务之间的通信,两者都是用于服务之间的通信
  • 从通信方式上来看
    RPC时双向直接网络通讯,而消息队列时单向引入中间载体的网络通讯
  • 从架构上来看
    消息队列时将消息存储起来,RPC则没有这个要求,RPC时双向直接网络童鞋你
  • 从请求处理的时效性来看
    RPC是同步请求,而消息队列是异步请求

kafka常见问题

kafka是什么

kafka是一个分布式的消息队列,它具有高吞吐量、低延迟、高容错性等特点,可以用于处理大量的数据,并保证数据的可靠性。

队列模型和kafka的消息模型

  • 队列模型
    队列模型是一种常见的消息传递模型,它将消息存储在一个队列中,并使用消费者来消费这些消息。队列模型通常用于异步处理和广播消息。
  • kafka的消息模型
    kafka的才写出模型使用发布订阅模型去解决这个问题,就比如我们使用主题作为消息通信载体,类似广播模式,发布者发布一条消息,改消息通过
    主题传递给所有的订阅者,在一条消息广播之才订阅的用户时收不到该条消息的,如果只有一个订阅者,那么他的模型和队列模型时基本一样的

kafkfa核心概念

  • producer
    生产者是消息的发布者,它可以将消息发送到kafka的topic中
  • consumer
    消费者是消息的订阅者,它可以从kafka的topic中消费消息
  • broker
    broker是kafka的服务器,它负责存储消息和处理消费者的请求
    同时我们可以注意到,topic和partition
  • topic: producer将消息发送到特定的的主题,consumer可以从特定的主题中消费消息
  • partition: 属于topic的一部分,一个topic可以有多个partition,通俗的可以理解为一个消息队列中的队列

zookeeper在kafka中的作用

  • broker注册
    在zookeeper上会有一个专门用来进行broker进行broker服务器列表的节点,每个broker在启动时都会向该节点进行注册,从而将broker服务器列表进行更新
  • topic注册
    在zookeeper上会有一个专门用来进行topic进行topic服务器列表的节点,每个topic在启动时都会向该节点进行注册,从而将topic服务器列表进行更新
  • 负载均衡
    当producer向kafka发送消息时,会根据topic找到对应的partition,并将消息发送到该partition所在的broker服务器上,从而实现负载均衡

kafkfa如何保证消息顺序,消息丢失和重复消费

  • 消息顺序
    kafka只能保证在partition中的消息顺序,不能保证在topic中的消息顺序
    每次进行添加到partition时,都会才用尾加发,kafka只能保证在partition中的消息顺序,不能保证在topic中的消息顺序
  • 消息丢失
    kafka有三种常见丢失消息的情况
    • 生产者丢失消息
      生产者丢失消息的原因可能是网络问题,或者producer在发送消息时发生了异常,从而导致消息丢失
    • 消费者丢失消息的情况
      在生产者给消费者消息的时候会给一个offset用来确认是否接受到消息,如果提交了offset后但是并没有接受到消息那么就会发生这种情况
    • kafka丢失消息
      kafka丢失消息的原因可能是kafka服务器发生了异常,或者kafka服务器发生了重启,从而导致消息丢失

kafka如何保证消息不重复消费

根本原因是消费者已经消费,但是没有提交offset
kafka侧由于服务端处理业务时间过长而导致了kafka认为服务假死
从而导致消费者重复消费

消费失败会怎样

在默认情况下,当消费异常会进行重试,重试多次后会跳过当前消息,继续进行后序消息的消费
默认情况下会进行消费10次数

业务思想

好难啊啊啊啊

  • 1. 首先使用构建增量索引作为广告检索服务
  • 2. 使用mysql中的Master-Slave协议,通过slave监听binlog日志实现日志,达到数据一致性的目的
  • 3. Kafka投递解析后的binlog日志,方便后续统计业务等,并维持索引(增量索引)。
  • 4. 检索广告的索引,实现条件匹配,并返回响应.

思考

  1. SpringCloud 和 Dubbo的选择问题,zuul和Gateway的选择问题
    SpringCloud和Dubbo从原理上和思想几乎一样,由于Springcloud由于更加完善的微服务
  2. Eureke中维护了Client中的哪些信息? 又怎样存储这些信息
    在其中注册了一个Instanceinfo实例,该实例中存储了Client的相关信息,如实例的id实例的ip地址,实例的端口号等
  3. 对数据表分层级的原因
    使用了逻辑分层
  • 标识表与表之间的依赖关系,比如Level3依赖于Level2,值,可以避免了出现空指针的代码,使用了依赖关系可以进行逐层检查
  • 表的逻辑分层可以简化了处理相同的业务逻辑的代码,比如Level2和Level3的表中都有相同的字段,那么我们可以将相同的字段进行提取,然后使用一个公共的类进行存储,从而简化代码
  1. 为什么要把全量数据导出到文件中,而不是直接从数据库中加载
    首先导出到文件需要放在公共的文件系统中
    服务是多实例存在,同时操作数据库会造成巨大的压力
  2. 为什么广告数据要放在JVM内存中,如果太多放不下怎么办
    我们将数据放在了concurrentHashMap中,这样就放在了JVM内存中,考虑到了快的原因
    对于第二个问题,使用数据hash分区的策略,我们可以进行将数据时分散到不同的分区里面,每台机器只维护少量的源信息
    其次owomf可以使用redis缓存系统, 由于广告数据的数据不大,我们不考虑
  3. Binlog是什么?如果监听的过程中,MySQL宕机了,再次启动服务,会是什么情况?
    Mysqlserver有四种类型的服务日志,error log,general query log,slow log,binlog
    其中binlog是用来记录数据库的变更的日志,可以用于数据恢复,数据同步等
    监听binlog有两种做法:
  • 不添加任何配置,自动监听最新的日志
  • 指定想要读取的binlog pos,记录指定位置的pos
    在每一次进行读取的时候我们只需要进行实时的记录每一次的postition就可以
  1. 为什么选取Binlog作为增量数据的收集方案
    其实是可行的,我们可以通过Ribbon,feign等框架进行负载均衡,从而实现数据的同步
    问题是代码冗余,实现起来我们需要在实现的时候进行写一份代码,然后将数据进行同步过去,有可能导致数据不稳定
    检索系统需要知道数据表的定义,广告检索系统应该是不知道数据表的定义的
    投放系统与检索系统之间存在严重的耦合
  2. 为什么要把BinLog的增量数据发送到Kafka上,微服务再去订阅kafka的信息
    如果不使用kafka,那么我们就会导致一个问题那就是会导致所有的服务实例进行监听Mysql服务器,会导致数据库的压力
    检索系统可以进行订阅kafka进行订阅