同学你好:
你给出的答案和解决方案都非常好,下面,我对两个问题做一些补充:
作业1:目前的实现,ad-search 就是 MySQL Master 的 Slave,如果部署多个 ad-search 实例,那个每个实例都是一个 Slave,这样合理吗 ?你能说出为什么吗 ?
每一个 ad-search 都作为 MySQL 的 Slave(可以查下 MySQL 的 Master/Slave 协议),当 Slave 的个数比较少的时候(比如业务量不大,且 Slave 个数不超过5个),是可以这么多的。但是当 Slave 个数变多,Binlog 将会由 MySQL Master 发往各个 Slave,这时候带宽、数据同步延迟、并发连接都会成为系统瓶颈(表面上看是 MySQL 的瓶颈,但实际却是系统架构设计的太为简单,没有考虑并发较高,需要多实例的场景)。所以,Slave 的个数是一定不能太多的,最好不要超过5个。但同时,ad-search 实例个数又可能会很多(因为流量较大,需要多实例分散流量),这就引出了作业2中提到的解决方案。
作业2:尝试实现一个微服务,核心是 KafkaSender.java,ad-search 去监听对应的 topic(message 即为 Binlog 增量),那么,此时只有这个微服务是 Slave。
实现这个微服务的核心思想并不复杂,其出发点就是让 Kafka 监听 Binlog 的微服务作为 MySQL 的 Slave。所以,这个微服务是独立存在的,更不能与 ad-search 发生“直接的”关系。
合理的方式是应该构建 ad-binlog-kafka(微服务名字可以随意)微服务,其单独负责监听 Binlog,伪装为 MySQL Slave,即服务 kafkaTemplate.send 的功能。
在 ad-search 中只需要监听 ad-binlog-kafka 中 send (对应的 topic)出来的 message 就可以了,例如如下的实现。
@Slf4j
@Component
public class BinlogConsumer {
private final ISender sender;
@Autowired
public BinlogConsumer(ISender sender) {
this.sender = sender;
}
@KafkaListener(topics = {"ad-search-mysql-data"}, groupId = "ad-search")
public void processMysqlRowData(ConsumerRecord<?, ?> record) {
Optional<?> kafkaMessage = Optional.ofNullable(record.value());
if (kafkaMessage.isPresent()) {
Object message = kafkaMessage.get();
MySqlRowData rowData = JSON.parseObject(
message.toString(),
MySqlRowData.class
);
log.info("kafka processMysqlRowData: {}", JSON.toJSONString(rowData));
sender.sender(rowData);
}
}
}
但是,此时需要注意到一些 Binlog 对象类应该是放到一个通用的 jar 包中,方便 ad-search 和 ad-binlog-kafka 的引用(或使用)。但是,并不应该是放在 ad-common 中。因为它是一个项目整体的通用 jar(统一响应、统一异常、统一配置),如果再增加其他的微服务,这些也都是通用的。而 Binlog 相关的类只与 ad-search 和 ad-binlog-kafka 相关,所以,比较好的方式是再构建一个通用的 jar,例如:ad-binlog-common。
欢迎来 QQ 群随时交流、讨论,也非常感谢同学的支持!