maxwell 是由美国zendesk开源,用java编写的Mysql实时抓取软件。 其抓取的原理也是基于binlog。
解压缩maxwell-1.25.0.tar.gz 到/opt/module目录下。
CREATE DATABASE maxwell ;
GRANT ALL ON maxwell.* TO 'maxwell'@'%' IDENTIFIED BY '123123';
GRANT SELECT ,REPLICATION SLAVE , REPLICATION CLIENT ON *.* TO maxwell@'%'
在任意位置建立maxwell.properties 文件(我选在/opt/module/maxwell-1.25.0)
producer=kafka
kafka.bootstrap.servers=hadoop102:9092,hadoop103:9092,hadoop104:9092
kafka_topic=ODS_DB_GMALL_M
host=hadoop102
user=maxwell
password=123123
client_id=maxwell_1
/opt/module/maxwell-1.25.0/bin/maxwell --config /opt/module/maxwell-1.25.0/maxwell.properties >/dev/null 2>&1 &
kafka-consumer.sh ODS_DB_GMALL_M
canal 每一条SQL会产生一条日志,如果该条Sql影响了多行数据,则已经会通过集合的方式归集在这条日志中。(即使是一条数据也会是数组结构)
maxwell 以影响的数据为单位产生日志,即每影响一条数据就会产生一条日志。如果想知道这些日志是否是通过某一条sql产生的可以通过xid进行判断,相同的xid的日志来自同一sql。
当原始数据是数字类型时,maxwell会尊重原始数据的类型不增加双引,变为字符串。
canal一律转换为字符串。
canal数据中会带入表结构。maxwell更简洁。
在scala\com\atguigu\gmall1122\realtime\app\ods\BaseDBMaxwellApp
import com.alibaba.fastjson.{JSON, JSONArray, JSONObject}
import com.atguigu.gmall.realtime.utils.{MyKafkaSinkUtil, MyKafkaUtil, OffsetManagerUtil}
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.TopicPartition
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, InputDStream}
import org.apache.spark.streaming.kafka010.{HasOffsetRanges, OffsetRange}
import org.apache.spark.streaming.{Seconds, StreamingContext}
object BaseDBMaxwellApp {
def main(args: Array[String]): Unit = {
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("ods_base_db_maxwell_app")
val ssc = new StreamingContext(sparkConf,Seconds(5))
val topic ="ODS_DB_GMALL_M";
val groupId="base_db_maxwell_group"
val offset: Map[TopicPartition, Long] = OffsetManagerUtil.getOffset(groupId,topic)
var inputDstream: InputDStream[ConsumerRecord[String, String]]=null
// 判断如果从redis中读取当前最新偏移量 则用该偏移量加载kafka中的数据 否则直接用kafka读出默认最新的数据
if(offset!=null&&offset.size>0){
inputDstream = MyKafkaUtil.getKafkaStream(topic,ssc,offset,groupId)
//startInputDstream.map(_.value).print(1000)
}else{
inputDstream = MyKafkaUtil.getKafkaStream(topic,ssc,groupId)
}
//取得偏移量步长
var offsetRanges: Array[OffsetRange] =null
val inputGetOffsetDstream: DStream[ConsumerRecord[String, String]] = inputDstream.transform { rdd =>
offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
rdd
}
val dbJsonObjDstream: DStream[JSONObject] = inputGetOffsetDstream.map { record =>
val jsonString: String = record.value()
val jsonObj: JSONObject = JSON.parseObject(jsonString)
jsonObj
}
dbJsonObjDstream.foreachRDD{rdd=>
rdd.foreachPartition{jsonObjItr=>
for (jsonObj <- jsonObjItr ) {
val dataObj: JSONObject = jsonObj.getJSONObject("data")
val tableName = jsonObj.getString("table")
val id = dataObj.getString("id")
val topic = "ODS_T_" + tableName.toUpperCase
if (tableName=="order_info"&&jsonObj.getString("type").equals("insert")){
MyKafkaSinkUtil.send(topic, id, dataObj.toJSONString)
}
}
}
OffsetManagerUtil.saveOffset(groupId,topic,offsetRanges)
}
ssc.start()
ssc.awaitTermination()
}
}