歡迎關(guān)注個(gè)人微信公眾號(hào): 小哈學(xué)Java, 每日推送 Java 領(lǐng)域干貨文章,關(guān)注即免費(fèi)無(wú)套路附送 100G 海量學(xué)習(xí)、面試資源喲!!
個(gè)人網(wǎng)站: https://www.exception.site/springboot/spring-boot2-kafka
什么是 Kafka?
Kafka 是 Apache 基金會(huì)開(kāi)源的一個(gè)分布式發(fā)布 - 訂閱消息中間件,流處理平臺(tái)。 它起源于 LinkedIn,由 Scala 和 Java兩種語(yǔ)言編寫(xiě)而成。于 2011 年成為 Apache 項(xiàng)目,2012 成為 Apache 基金會(huì)下頂級(jí)項(xiàng)目。
Kafka 專(zhuān)為分布式高吞吐系統(tǒng)而設(shè)計(jì)。相比較其他消息中間件,如 RabbitMq 等,Kafka 具有更好的吞吐量,內(nèi)置分區(qū),復(fù)制和固有的容錯(cuò)能力,使得它非常適合應(yīng)用在大數(shù)據(jù)領(lǐng)域。另外,Kafka 還支持離線、在線消費(fèi)消息。
為什么要用 Kafka
- 低延遲 - Kafka 支持低延遲消息傳遞,速度極快,能達(dá)到 200w 寫(xiě)/秒;
- 高性能 - Kafka對(duì)于消息的發(fā)布、訂閱都具有高吞吐量。即使存儲(chǔ)了 TB 級(jí)的消息,依然能夠保證穩(wěn)定的性能;
- 可靠性 - Kafka 是分布式,分區(qū),復(fù)制和容錯(cuò)的,保證零停機(jī)和零數(shù)據(jù)丟失。
- 可拓展性 - Kafka 支持集群水平拓展。
- 耐用性 - Kafka 使用"分布式提交日志",消息能夠快速的持久化的磁盤(pán)上。
Kafka 環(huán)境安裝
接下來(lái),小哈為大家演示一下,在 Linux 系統(tǒng)中,采用最簡(jiǎn)單的單機(jī)安裝方式, 因?yàn)楸疚闹攸c(diǎn)還是介紹 Spring Boot 2.x 快速集成整合 Kafka.
下載 Kafka
訪問(wèn) Kafka 官網(wǎng) http://kafka.apache.org/downloads,下載 tgz 包, 這里演示版本為最新的 2.3.0 版本。
解壓,進(jìn)入目錄
下載下來(lái)過(guò)后,放置到指定位置,執(zhí)行命令解壓:
tar -zxvf kafka_2.11-2.3.0.tgz
解壓完成后,進(jìn)入 Kafka 目錄下:
cd kafka_2.11-2.3.0
啟動(dòng) zookeeper
通過(guò) bin 目錄下的 zookeeper-server-start.sh
啟動(dòng)腳本,來(lái)啟動(dòng) zk 單節(jié)點(diǎn)實(shí)例:
bin/zookeeper-server-start.sh -daemon config/zookeeper.properties
啟動(dòng) Kafka
通過(guò) bin 目錄下的 kafka-server-start.sh
來(lái)啟動(dòng) :
bin/kafka-server-start.sh config/server.properties
注意:Kafka 默認(rèn)使用 9092 端口,注意關(guān)閉防火墻,阿里云服務(wù)器的話(huà),記得添加安全組。
Spring Boot 2.x 開(kāi)始整合
新建一個(gè) Spring Boot 2.x Web 工程。
項(xiàng)目結(jié)構(gòu)
添加 maven 依賴(lài)
小哈這里完整的 maven 依賴(lài)如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>site.exception</groupId>
<artifactId>spring-boot-kafka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-kafka</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 阿里巴巴 fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
添加 kafka 配置
修改 application.yml 文件,添加 kafka 相關(guān)配置:
spring:
kafka:
# 指定 kafka 地址,我這里在本地,直接就 localhost, 若外網(wǎng)地址,注意修改【PS: 可以指定多個(gè)】
bootstrap-servers: localhost:9092
consumer:
# 指定 group_id
group-id: group_id
auto-offset-reset: earliest
# 指定消息key和消息體的編解碼方式
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
producer:
# 指定消息key和消息體的編解碼方式
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
關(guān)于 auto-offset-reset
auto.offset.reset
配置有3個(gè)值可以設(shè)置,分別如下:
-
earliest:當(dāng)各分區(qū)下有已提交的
offset
時(shí),從提交的offset
開(kāi)始消費(fèi);無(wú)提交的offset
時(shí),從頭開(kāi)始消費(fèi); -
latest:當(dāng)各分區(qū)下有已提交的
offset
時(shí),從提交的offset
開(kāi)始消費(fèi);無(wú)提交的offset
時(shí),消費(fèi)新產(chǎn)生的該分區(qū)下的數(shù)據(jù); -
none:
topic
各分區(qū)都存在已提交的offset
時(shí),從offset
后開(kāi)始消費(fèi);只要有一個(gè)分區(qū)不存在已提交的offset
,則拋出異常;
默認(rèn)建議用 earliest
, 設(shè)置該參數(shù)后 kafka出錯(cuò)后重啟,找到未消費(fèi)的offset可以繼續(xù)消費(fèi)。
而 latest 這個(gè)設(shè)置容易丟失消息,假如 kafka 出現(xiàn)問(wèn)題,還有數(shù)據(jù)往topic中寫(xiě),這個(gè)時(shí)候重啟kafka,這個(gè)設(shè)置會(huì)從最新的offset開(kāi)始消費(fèi), 中間出問(wèn)題的哪些就不管了。
none 這個(gè)設(shè)置沒(méi)有用過(guò),兼容性太差,經(jīng)常出問(wèn)題。
新增一個(gè)訂單類(lèi)
模擬業(yè)務(wù)系統(tǒng)中,用戶(hù)每下一筆訂單,就發(fā)送一個(gè)消息,供其他服務(wù)消費(fèi):
/**
* @author 犬小哈(公眾號(hào):小哈學(xué)Java)
* @date 2019/4/12
* @time 下午3:05
* @discription 訂單實(shí)體類(lèi)
**/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Order {
/**
* 訂單id
*/
private long orderId;
/**
* 訂單號(hào)
*/
private String orderNum;
/**
* 訂單創(chuàng)建時(shí)間
*/
private LocalDateTime createTime;
}
添加一個(gè)消息發(fā)布者
新建一個(gè) KafkaProvider
消息提供者類(lèi),源碼如下:
/**
* @author 犬小哈(公眾號(hào):小哈學(xué)Java)
* @date 2019/4/12
* @time 下午3:05
* @discription 消息提供者
**/
@Component
@Slf4j
public class KafkaProvider {
/**
* 消息 TOPIC
*/
private static final String TOPIC = "xiaoha";
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(long orderId, String orderNum, LocalDateTime createTime) {
// 構(gòu)建一個(gè)訂單類(lèi)
Order order = Order.builder()
.orderId(orderId)
.orderNum(orderNum)
.createTime(createTime)
.build();
// 發(fā)送消息,訂單類(lèi)的 json 作為消息體
ListenableFuture<SendResult<String, String>> future =
kafkaTemplate.send(TOPIC, JSONObject.toJSONString(order));
// 監(jiān)聽(tīng)回調(diào)
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
@Override
public void onFailure(Throwable throwable) {
log.info("## Send message fail ...");
}
@Override
public void onSuccess(SendResult<String, String> result) {
log.info("## Send message success ...");
}
});
}
}
添加一個(gè)消息消費(fèi)者
消息發(fā)送出去了,當(dāng)然就需要一個(gè)消費(fèi)者,消費(fèi)者拿到消息后,再做相關(guān)的業(yè)務(wù)處理,這里,小哈僅僅是打印消息體。
添加 KafkaConsumer
消費(fèi)者類(lèi):
/**
* @author 犬小哈(公眾號(hào):小哈學(xué)Java)
* @date 2019/4/12
* @time 下午3:05
* @discription 消息消費(fèi)者
**/
@Component
@Slf4j
public class KafkaConsumer {
@KafkaListener(topics = "xiaoha", groupId = "group_id")
public void consume(String message) {
log.info("## consume message: {}", message);
}
}
通過(guò) @KafkaListener
注解,我們可以指定需要監(jiān)聽(tīng)的 topic
以及 groupId
, 注意,這里的 topics
是個(gè)數(shù)組,意味著我們可以指定多個(gè) topic
,如:@KafkaListener(topics = {"xiaoha", "xiaoha2"}, groupId = "group_id")
。
注意:消息發(fā)布者的 TOPIC 需要保持與消費(fèi)者監(jiān)聽(tīng)的 TOPIC 一致,否者消費(fèi)不到消息。
單元測(cè)試
新建單元測(cè)試,功能測(cè)試消息發(fā)布,以及消費(fèi)。
/**
* @author 犬小哈(公眾號(hào):小哈學(xué)Java)
* @date 2019/4/12
* @time 下午3:05
* @discription
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootKafkaApplicationTests {
@Autowired
private KafkaProvider kafkaProvider;
@Test
public void sendMessage() throws InterruptedException {
// 發(fā)送 1000 個(gè)消息
for (int i = 0; i < 1000; i++) {
long orderId = i+1;
String orderNum = UUID.randomUUID().toString();
kafkaProvider.sendMessage(orderId, orderNum, LocalDateTime.now());
}
TimeUnit.MINUTES.sleep(1);
}
}
發(fā)送 1000 個(gè)消息,看消息是否能夠被正常發(fā)布與消費(fèi),控制臺(tái)日志如下:
可以發(fā)現(xiàn),1000 個(gè)消息被成功發(fā)送,且被正常消費(fèi)。
我們?cè)衮?yàn)證下 Kafka 的 topic 列表,看 xiaoha
這個(gè)topic
是否正常被創(chuàng)建, 執(zhí)行 bin
目錄下查看 topic
列表的 kafka-topics.sh
腳本:
bin/kafka-topics.sh --list --zookeeper localhost:2181
好了,大功告成!
總結(jié)
小哈今天主要和大家分享了,如何安裝單機(jī)版的 kafka 環(huán)境、如何在 Spring Boot 2.x 中快速集成消息中間件 Kafka,以及演示了相關(guān)示例代碼來(lái)發(fā)布消息、消費(fèi)消息,希望大家看完過(guò)后有所收獲,下期見(jiàn)!
GitHub 源碼地址
https://github.com/weiwosuoai/spring-boot-tutorial/tree/master/spring-boot-kafka
參考資料
https://zh.wikipedia.org/wiki/Kafka
https://www.w3cschool.cn/apache_kafka/
https://juejin.im/post/5d406a925188255d352ab24e
http://www.lxweimin.com/p/e1df7d18bb8f
免費(fèi)分享 | 面試&學(xué)習(xí)福利資源
最近在網(wǎng)上發(fā)現(xiàn)一個(gè)不錯(cuò)的 PDF 資源《Java 核心知識(shí)&面試.pdf》分享給大家,不光是面試,學(xué)習(xí),你都值得擁有!!!
獲取方式: 關(guān)注公眾號(hào): 小哈學(xué)Java, 后臺(tái)回復(fù)資源,既可免費(fèi)無(wú)套路獲取資源鏈接,下面是目錄以及部分截圖:
重要的事情說(shuō)兩遍,關(guān)注公眾號(hào): 小哈學(xué)Java, 后臺(tái)回復(fù)資源,既可免費(fèi)無(wú)套路獲取資源鏈接 !!!