一起养成写作习惯!这是我参与「掘金日新计划 · 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
使用信号量来处理网关的线程:
比刚刚好了一些但是还有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;
}
}
然后起两个前置生产者和一个消费者下单。
/**
* 消费者示例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测试接口: 库存都售磬了
查看订单数
正正好好一百个没有超卖