springcloud 实战(3)

122 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

前言

上文我们已经搭建l由Zuul和Eureka整合起来以后利用框架Ribben的微服务基础框供;网关的限流能力,主要在Zuul的过滤器功能实现。然后我们发现微服务之间的调用很容易出现熔断,因为服务的互相调用的成本是非常高的。我们这里先进行第一步的改造,下单成功以后的数据库操作由微服务处理,改为直接通过kafak的队列去处理订单。

zuul网关

首先接前文的问题,为什么我们的zuul网关仅仅100个请求就打崩了呢。看看zuul的配置

zuul:
 ribbonIsolationStrategy: THREAD

我们知道zuul有两种隔离策略,一种是线程级的,比较安全,但是承载力较差。基本上一个线程池10个线程,其实可以多起网关的机器 zuul1-zuul2这样均衡负载,也可以在网关调用后端的部分改为队列。

我们这里先把配置改为SEMAPHORE,因为我们的下单逻辑非常简单,这样也不会有太大影响

zuul:
  ribbonIsolationStrategy: SEMAPHORE
  semaphore:
    max-semaphores: 200

使用信号量来处理网关的线程:

屏幕快照 2022-04-29 下午10.43.14.png 比刚刚好了一些但是还有25个订单没有下单成功,这里如何去优化这个问题呢,只能使用消息队列了

消息队列

如何安装启动kafak这里就不赘述了。这里先引入pom文件

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

引入配置文件

kafka:
  bootstrap-servers:  127.0.0.1:9092
  #=============== producer  =======================
  producer:
    #如果该值大于零时,表示启用重试失败的发送次数
    retries: 0
    #每当多个记录被发送到同一分区时,生产者将尝试将记录一起批量处理为更少的请求,默认值为16384(单位字节)
    batch-size: 16384
    #生产者可用于缓冲等待发送到服务器的记录的内存总字节数,默认值为3355443
    buffer-memory: 33554432
    #key的Serializer类,实现类实现了接口org.apache.kafka.common.serialization.Serializer
    key-serializer: org.apache.kafka.common.serialization.StringSerializer
    #value的Serializer类,实现类实现了接口org.apache.kafka.common.serialization.Serializer
    value-serializer: org.apache.kafka.common.serialization.StringSerializer
  #=============== consumer  =======================
  consumer:
    #用于标识此使用者所属的使用者组的唯一字符串
    group-id: test-consumer-group
    #当Kafka中没有初始偏移量或者服务器上不再存在当前偏移量时该怎么办,默认值为latest,表示自动将偏移重置为最新的偏移量
    #可选的值为latest, earliest, none
    auto-offset-reset: earliest
    #消费者的偏移量将在后台定期提交,默认值为true
    enable-auto-commit: true
    #如果'enable-auto-commit'为true,则消费者偏移自动提交给Kafka的频率(以毫秒为单位),默认值为5000。
    auto-commit-interval: 100
    #密钥的反序列化器类,实现类实现了接口org.apache.kafka.common.serialization.Deserializer
    key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    #值的反序列化器类,实现类实现了接口org.apache.kafka.common.serialization.Deserializer
    value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

然后写一个demo测试

@Component
public class KafkaService {
    private static final Logger LOGGER = Logger.getLogger(KafkaService.class.getName());
    @Resource
    private KafkaUtils kafkaUtils;

    /**
     * 生产者往topic中发送消息demo
     *
     * @param topic
     * @param message
     * @return
     */
    @PostMapping("kafka/message")
    public  boolean sendMessage(String topic, String message) {
        kafkaUtils.sendMessage(topic, message);
        return true;
    }

  
}

然后起两个前置生产者和一个消费者下单。

屏幕快照 2022-04-30 上午12.11.37.png

/**
 * 消费者示例demo
 * <p>
 * 基于注解监听多个topic,消费topic中消息
 * (注意:如果监听的topic不存在则会自动创建)
 */
@KafkaListener(topics = {"topic1"})
public void consume(String message) {

    LOGGER.info("receive msg: " + message );
    SeckillOrderRequestDTO dto= JSON.parseObject(message,SeckillOrderRequestDTO.class);
    redissionOrderService.saveOrder(dto.getGoodId());

}

消费者收到消息以后下单,前端请求均匀的打在两个前置的处理中。 如果后端请求流程多也可以非常简单的加服务。

然后再次用jmeter测试接口: 库存都售磬了

屏幕快照 2022-04-30 上午12.33.13.png 查看订单数

屏幕快照 2022-04-30 上午12.34.43.png 正正好好一百个没有超卖

总结