引言
上一篇中提到了,go 连接 kafka 进行消息的生产和消费过程。在这一篇中,将对 go 连接 kafka 写 mysql 进行简单的设计和实现。
本文主要针对的是 Mac 系统,如果使用其它操作系统,操作过程可能有所差异,请注意区别。
一、环境安装
可以根据上一篇的介绍搭建好 kafka,在这里不做赘述。
安装 mysql
我安装的是 mysql 的5.8版本,在 mysql 官网下载安装即可。
http://www.mysql.com/
详细的安装过程,可以参考下面的链接:
https://www.jianshu.com/p/07a9826898c0
二、代码
go 语言访问 mysql,需要第三方依赖,我采用的是 go-sql-driver/mysql,在这里也针对 go-sql-driver/mysql 进行操作。可以使用以下命令获得该依赖:
go get github.com/go-sql-driver/mysql
建立 test.go 文件,代码如下:
func main() {
// 用户名:密码@tcp(ip:port)/dbname
db, err := sql.Open("mysql", "root:12345678@tcp(localhost:3306)/test")
if err != nil {
panic(err.Error())
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err.Error())
}
fmt.Println("connected to MySQL...")
stmtIns, err := db.Prepare("INSERT INTO datadump (`topic`,`partition`,`offset`,`key`,`value`,`processedby`,`createdat`) VALUES(?,?,?,?,?,?,?)")
if err != nil {
panic(err.Error())
}
defer stmtIns.Close()
ehcsBroker := os.Getenv("OEHCS_EXTERNAL_CONNECT_STRING")
if ehcsBroker == "" {
ehcsBroker = "localhost:9092"
}
ehcsTopic := os.Getenv("OEHCS_TOPIC")
if ehcsTopic == "" {
ehcsTopic = "test"
}
config := cluster.NewConfig()
config.Consumer.Return.Errors = true
config.Group.Return.Notifications = true
brokers := []string{ehcsBroker}
topics := []string{ehcsTopic}
fmt.Println("Connecting to EHCS cluster at " + ehcsBroker)
consumer, err := cluster.NewConsumer(brokers, "test-consumer-group", topics, config)
if err != nil {
panic(err)
}
fmt.Println("connected to Kafka...")
defer consumer.Close()
//get ACCS app instance name
appName := os.Getenv("ORA_APP_NAME")
if appName == "" {
appName = "accsgokafkamysql"
}
appInstance := os.Getenv("ORA_INSTANCE_NAME")
if appInstance == "" {
appInstance = "instance1"
}
processedby := appName + "_" + appInstance
fmt.Println("Processed by instance " + processedby)
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
go func() {
for err := range consumer.Errors() {
log.Printf("Error: %s\n", err.Error())
}
}()
go func() {
for ntf := range consumer.Notifications() {
log.Printf("Rebalanced: %+v\n", ntf)
}
}()
for {
select {
case msg, ok := <-consumer.Messages():
if ok {
fmt.Fprintf(os.Stdout, "%s/%d/%d\t%s\t%s\n", msg.Topic, msg.Partition, msg.Offset, msg.Key, msg.Value)
_, err = stmtIns.Exec(msg.Topic, msg.Partition, msg.Offset, msg.Key, msg.Value, processedby, time.Now().Local())
if err != nil {
panic(err.Error())
} else {
fmt.Println("Detailed pushed to MySQL")
}
consumer.MarkOffset(msg, "")
}
case <-signals:
return
}
}
}
说明:代码包括两个部分,一个是建立与 mysql 的连接,另一个是启动 kafka 消费者接收消息并插入到 datadump 表格中。
创建 send.go 文件
func syncProducer(address []string, count int) {
log.Println("this count is %d", count)
t1 := time.Now() // get current time
config := sarama.NewConfig()
config.Producer.Return.Successes = true
config.Producer.Timeout = 5 * time.Second
p, err := sarama.NewSyncProducer(address, config)
if err != nil {
log.Printf("sarama.NewSyncProducer err, message=%s \n", err)
return
}
defer p.Close()
topic := "test"
srckey := "%d"
srcValue := "this value is index=%d"
for i:=0; i<10; i++ {
key := fmt.Sprintf(srckey,i)
value := fmt.Sprintf(srcValue, i)
msg := &sarama.ProducerMessage{
Topic:topic,
Key:sarama.ByteEncoder(key),
Value:sarama.ByteEncoder(value),
}
part, offset, err := p.SendMessage(msg)
if err != nil {
log.Printf("send message(%s) err=%s \n", value, err)
}else {
fmt.Fprintf(os.Stdout, value + "发送成功,partition=%d, offset=%d \n", part, offset)
}
time.Sleep(2*time.Second)
}
elapsed := time.Since(t1)
log.Println("发送消息时间耗时: %d", elapsed)
}
datadump表
CREATE TABLE `datadump` (
`uid` INT(10) NOT NULL AUTO_INCREMENT,
`topic` VARCHAR(64) NULL DEFAULT NULL,
`partition` INT(64) NULL DEFAULT NULL,
`offset` INT(64) NULL DEFAULT NULL,
`key` VARCHAR(64) NULL DEFAULT NULL,
`value` VARCHAR(64) NULL DEFAULT NULL,
`processedby` VARCHAR(64) NULL DEFAULT NULL,
`createdat` VARCHAR(64) NULL DEFAULT NULL,
PRIMARY KEY (`uid`)
);
三、流程说明
具体的操作过程如下:
- 启动 zookeeper 和 kafka
- 启动 mysql
使用命令
mysql -u root -p
创建数据库
create DATABASE test;
切换到 test 数据库
use test;
输入要创建的表 datadump内容
CREATE TABLE `datadump` (
`uid` INT(10) NOT NULL AUTO_INCREMENT,
`topic` VARCHAR(64) NULL DEFAULT NULL,
`partition` INT(64) NULL DEFAULT NULL,
`offset` INT(64) NULL DEFAULT NULL,
`key` VARCHAR(64) NULL DEFAULT NULL,
`value` VARCHAR(64) NULL DEFAULT NULL,
`processedby` VARCHAR(64) NULL DEFAULT NULL,
`createdat` VARCHAR(64) NULL DEFAULT NULL,
PRIMARY KEY (`uid`)
);
- 启动一个终端,到代码目录下运行 go run send.go
- 新启动一个终端,到目录运行 go run test.go
- 查表select * from datadump
如图所示,kafka 发送的消息,被写入了 mysql 的表中。
四、问题说明
1、mysql 无法连接,sql.Open 失败;
2、mysql 连接拒绝,Ping() 不同;
以上问题可以尝试重新安装 mysql 后,重启电脑尝试;
3、mysql “table doesn’t exist”,进入 mysql, 新建数据库和表。
操作过程中遇到问题难免,沉住气,多尝试,可以搜索一下看是否能够获取到解决问题的思路。
五、参考资料
https://github.com/abhirockzz/accs-go-kafka-mysql
http://www.runoob.com/mysql/mysql-create-tables.html