Spark雙流join-延遲資料--double_happy
目的:
Spark流式處理是微批次進行處理的
那麼雙流join 的時候 如何保證各個批次 以及跨批次進行join呢???
Spark流處理進行雙流join:
1.延遲資料會join不上
2.該如何join
問題
Spark雙流join可能發生的情況:
1.左右
2.無右
3.左無
注意:
左右分佈代表 不同的流 有資料
無表示 沒有資料
即:
左無:就是左邊有資料,右邊沒有資料
解決思路:
下圖
測試
Spark雙流join問題展現
這裡就不已Kafka資料進行測試 :
使用sock資料即可
先測試資料是否打通:
code:
package code.com.hivemetabi.task
import java.io.Serializable
import code.com.common.util.ParserUtil
import code.com.hivemetabi.bean.TechBean.OrderInfo
import code.com.hivemetabi.bean.TechBean.Order
import com.common.util.ContextUtil
import org.apache.flink.api.java.utils.ParameterTool
/**
* author : sxwang
* date : 2020/11/13 9:36
* version: 1.0
*/
class MultiStreamJoinTask(params: ParameterTool) extends Serializable {
private val className = "MultiStreamJoinTask"
private val jobName = s"bi_${className}"
private val batch: Int = params.getRequired("batch").toInt
private val host: String = params.getRequired("host")
private val port1 = params.getRequired("port1").toInt
private val port2 = params.getRequired("port2").toInt
def execute={
val ssc = ContextUtil.getStreamingContext(jobName, batch)
val s1 = ssc.socketTextStream(host,port1)
.map(data=>{
val fileds = data.split(",")
(fileds(0),ParserUtil.arrConvert2CaseClass[Order](classOf[Order], fileds, 2))
})
val s2 = ssc.socketTextStream(host,port2)
.map(data=>{
val fileds = data.split(",")
(fileds(0),ParserUtil.arrConvert2CaseClass[OrderInfo](classOf[OrderInfo], fileds, 4))
})
//join
s1.fullOuterJoin(s2).print()
ssc.start()
ssc.awaitTermination()
}
}
object MultiStreamJoinTask {
def apply(params: ParameterTool): MultiStreamJoinTask = new MultiStreamJoinTask(params)
def main(args: Array[String]): Unit = {
val parameterTool = ParameterTool.fromArgs(args)
MultiStreamJoinTask(parameterTool).execute
}
}
package code.com.hivemetabi.bean
/**
* author : sxwang
* date : 2020/11/13 9:48
* version: 1.0
*/
object TechBean {
case class Order(orderId:String,orderNum:String)
case class OrderInfo(orderId:String,userName:String,skuName:String,skuNum:String)
case class OrderDetail(var orderId:String,var orderNum:String, var userName:String,var skuName:String,var skuNum:String){
def builderOrder(order:Order): OrderDetail ={
if(null!=order) {
this.orderId = order.orderId
this.orderNum = order.orderNum
}
this
}
def builderOrderInfo(orderInfo:OrderInfo):OrderDetail={
if(null!=orderInfo) {
this.userName=orderInfo.userName
this.skuName=orderInfo.skuName
this.skuNum=orderInfo.skuNum
}
this
}
}
}
結果1:
輸入資料:
port : 8888 8889
8888:
1,200
2,100
3,300
8889 :
1,sxwang,spark,2
1,ygy,flink,3
2,mm,miao,100
3,xmm,miao2,200
結果:
join 的三種情況:
左右:
(2,(Some(Order(2,100)),Some(OrderInfo(2,mm,miao,100))))
(3,(Some(Order(3,300)),Some(OrderInfo(3,xmm,miao2,200))))
(1,(Some(Order(1,200)),Some(OrderInfo(1,sxwang,spark,2))))
(1,(Some(Order(1,200)),Some(OrderInfo(1,ygy,flink,3))))
無右:
(2,(None,Some(OrderInfo(2,mm,miao,100))))
(3,(None,Some(OrderInfo(3,xmm,miao2,200))))
(1,(None,Some(OrderInfo(1,sxwang,spark,2))))
(1,(None,Some(OrderInfo(1,ygy,flink,3))))
左無:
(2,(Some(Order(2,100)),None))
(3,(Some(Order(3,300)),None))
(1,(Some(Order(1,200)),None))
結論:
因為上面程式碼裡面:
沒有對 join 的情況進行做處理
所以 結果會有三種情況
這就是 Spark雙流join 的問題!!
改進:
因為上面的join 你自己是不知道 到底 哪一邊沒有join上
稍微改進一下
package code.com.hivemetabi.task
import java.io.Serializable
import code.com.common.util.ParserUtil
import code.com.hivemetabi.bean.TechBean.{Order, OrderDetail, OrderInfo}
import com.common.util.ContextUtil
import org.apache.flink.api.java.utils.ParameterTool
/**
* author : sxwang
* date : 2020/11/13 9:36
* version: 1.0
*/
class MultiStreamJoinTask(params: ParameterTool) extends Serializable {
private val className = "MultiStreamJoinTask"
private val jobName = s"bi_${className}"
private val batch: Int = params.getRequired("batch").toInt
private val host: String = params.getRequired("host")
private val port1 = params.getRequired("port1").toInt
private val port2 = params.getRequired("port2").toInt
def execute={
val ssc = ContextUtil.getStreamingContext(jobName, batch)
val s1 = ssc.socketTextStream(host,port1)
.map(data=>{
val fileds = data.split(",")
(fileds(0),ParserUtil.arrConvert2CaseClass[Order](classOf[Order], fileds, 2))
})
val s2 = ssc.socketTextStream(host,port2)
.map(data=>{
val fileds = data.split(",")
(fileds(0),ParserUtil.arrConvert2CaseClass[OrderInfo](classOf[OrderInfo], fileds, 4))
})
//join
s1.fullOuterJoin(s2).map({
case (orderId,(Some(order),Some(orderInfo))) =>{
OrderDetail().builderOrder(order).builderOrderInfo(orderInfo)
}
case (orderId,(None,Some(orderInfo))) =>{
println("左邊沒有匹配上")
}
case (orderId,(Some(order),None)) =>{
println("右邊沒有匹配上")
}
case _=> Nil
}).print()
ssc.start()
ssc.awaitTermination()
}
}
object MultiStreamJoinTask {
def apply(params: ParameterTool): MultiStreamJoinTask = new MultiStreamJoinTask(params)
def main(args: Array[String]): Unit = {
val parameterTool = ParameterTool.fromArgs(args)
MultiStreamJoinTask(parameterTool).execute
}
}
結果:
左邊沒有匹配上
左邊沒有匹配上
左邊沒有匹配上
-------------------------------------------
Time: 1605236390000 ms
-------------------------------------------
()
()
()
右邊沒有匹配上
右邊沒有匹配上
-------------------------------------------
Time: 1605236400000 ms
-------------------------------------------
()
()
-------------------------------------------
Time: 1605236410000 ms
-------------------------------------------
OrderDetail(3,300,xmm,miao2,200)
-------------------------------------------
Time: 1605236420000 ms
-------------------------------------------
-------------------------------------------
Time: 1605236430000 ms
-------------------------------------------
-------------------------------------------
Time: 1605236440000 ms
-------------------------------------------
-------------------------------------------
Time: 1605236450000 ms
-------------------------------------------
-------------------------------------------
Time: 1605236460000 ms
-------------------------------------------
右邊沒有匹配上
右邊沒有匹配上
右邊沒有匹配上
-------------------------------------------
Time: 1605236470000 ms
-------------------------------------------
()
()
()
-------------------------------------------
Time: 1605236480000 ms
-------------------------------------------
左邊沒有匹配上
左邊沒有匹配上
左邊沒有匹配上
左邊沒有匹配上
-------------------------------------------
Time: 1605236490000 ms
-------------------------------------------
()
()
()
()
-------------------------------------------
Time: 1605236500000 ms
-------------------------------------------
-------------------------------------------
Time: 1605236510000 ms
-------------------------------------------
-------------------------------------------
Time: 1605236520000 ms
-------------------------------------------
OrderDetail(2,100,mm,miao,100)
OrderDetail(3,300,xmm,miao2,200)
OrderDetail(1,200,sxwang,spark,2)
OrderDetail(1,200,ygy,flink,3)
-------------------------------------------
Time: 1605236530000 ms
-------------------------------------------
解析結果:
左邊沒有匹配上:說明左邊沒有資料,右邊有資料
右邊沒有匹配上:說明右邊沒有資料,左邊有資料
注意:
我左邊輸入的資料: 3條
1,200
2,100
3,300
右邊輸入的資料: 4條
1,sxwang,spark,2
1,ygy,flink,3
2,mm,miao,100
3,xmm,miao2,200
檢視有一個的結果:
左邊沒有匹配上
左邊沒有匹配上
左邊沒有匹配上
-------------------------------------------
Time: 1605236390000 ms
-------------------------------------------
()
()
()
右邊沒有匹配上
右邊沒有匹配上
-------------------------------------------
Time: 1605236400000 ms
-------------------------------------------
()
()
-------------------------------------------
Time: 1605236410000 ms
-------------------------------------------
OrderDetail(3,300,xmm,miao2,200)
說明 :
右邊4條匹配上1條
左邊3條匹配上1條
結果就是 :
匹配上一條
那麼 如何都匹配上,就是我們這篇文章的重點!!!!
解決:
上面圖片開始提出了思路,基於次之上給與總結:
1.
與flink流的join原理不同的是:
Spark雙流join是對倆個流做滿外連線 ,
因為網路延遲等關係,不能保證每個視窗中的資料key都能匹配上,
這樣勢必會出現三種情況:
(some,some),(None,some),(Some,None)
2.根據這三種情況,下面做一下詳細解析:
(some,some)——
1號流和2號流中key能正常進行邏輯運算,
但是考慮到2號流後續可能會有剩下的資料到來,
所以需要將1號流中的key儲存到redis,以等待接下來的資料
(None,Some)——
找不到1號流中對應key的資料,
需要去redis中查詢1號流的快取,如果找不到,
則快取起來,等待1號流
(Some,None)——
找不到2號流中的資料,需要將key儲存到redis,以等待接下來的資料,
並且去reids中找2號流的快取,如果有,則join,然後刪除2號流的快取
這裡的中間快取可以使用:
redis、hbase、phoenix、clickhouse 很多
alluxio 不建議使用 為了做雙流join 使用它 維護成本太高 完全沒有必要
代續
相關文章
- Redis資料操作長延遲分析Redis
- Oracle資料庫密碼延遲驗證Oracle資料庫密碼
- MySQL 中讀寫分離資料延遲MySql
- 轉化率模型之轉化資料延遲模型
- mysql的主從複製資料延遲問題MySql
- RabbitMQ延遲訊息的延遲極限是多少?MQ
- Restate:支援JavaScript/Java的Rust低延遲持久工作流RESTJavaScriptRust
- 延遲釋出
- [20210529]延遲開啟資料庫.txt資料庫
- Laravel 延遲佇列Laravel佇列
- WebGL之延遲著色Web
- Mybatis延遲查詢MyBatis
- 疫情延遲 題解
- redis 延遲佇列Redis佇列
- SQL資料庫開發中的SSIS 延遲驗證方法SQL資料庫
- 教你如何解決MySQL資料延遲跳動的問題MySql
- 實現簡單延遲佇列和分散式延遲佇列佇列分散式
- 基於rabbitmq延遲外掛實現分散式延遲任務MQ分散式
- MySQL主從資料庫同步延遲問題怎麼解決MySql資料庫
- 一種透過延遲事務提升資料庫效能的方法資料庫
- MongoDB從庫延遲讀取資料問題的解決思路MongoDB
- 延遲阻塞佇列 DelayQueue佇列
- SQL之延遲約束SQL
- script的延遲執行
- zookeeper之watch事件延遲事件
- oracle的延遲約束Oracle
- hyperf redis延遲佇列Redis佇列
- 從庫延遲案例分析
- MySQL:雙主單寫 主庫偶爾出現大量延遲的原因MySql
- PostgreSQL 13 同步流複製+延遲備庫(#2.5)-202104SQL
- Spark拉取Kafka的流資料,轉插入HBase中SparkKafka
- 美國伺服器延遲高怎麼辦,如何解決延遲問題伺服器
- PostgreSQL 13 非同步流複製+延遲備庫(#2.2)-202103SQL非同步
- RabbitMQ實戰《延遲佇列》MQ佇列
- mysql主從延遲複製MySql
- RabbitMQ實現延遲佇列MQ佇列
- RabbitMQ 實現延遲佇列MQ佇列
- Mybatis延遲載入、快取MyBatis快取