Flink 自定義維表

新手路上的程式設計師發表於2019-05-07

寫這個部落格主要是看了袋鼠雲的flinkStreamSQL git地址:https://github.com/DTStack/flinkStreamSQL  自己還往上提交了kudu的sink和side 第一次commit到github上面還是很開心的。

這裡重點說的是flinkStreamSQL是如何完成side的,主要其實是兩種快取方案LRU和ALL。這裡忽略所有的sql解析 註冊等等,單純的從流的角度完成維表join。

ALL相對比較簡單先介紹ALL: 
從KuduAllReqRow開始,這裡是維表的載入以及如何join。先檢視繼承關係,只看需要關心的。先看AllReqRow,AllReqRow只需要關心open()方法。這裡是同步快取,快取完畢後資料才繼續往下走。

     @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        //初始化全量維表資料
        initCache();
        System.out.println("----- all cacheRef init end-----");

        //start reload cache thread
        SideTableInfo sideTableInfo = sideInfo.getSideTableInfo();
        //建立執行緒池 開啟排程執行緒 每隔一段時間查詢全量資料 覆蓋原有資料
        es = Executors.newSingleThreadScheduledExecutor(new DTThreadFactory("cache-all-reload"));
        es.scheduleAtFixedRate(() -> reloadCache(), sideTableInfo.getCacheTimeout(), sideTableInfo.getCacheTimeout(), TimeUnit.MILLISECONDS);
    }

這裡其實就是主要的思想了,開啟一個排程執行緒不停的去查詢資料然後快取。這裡快取用的是
AtomicReference<Map<String, List<Map<String, Object>>>> cacheRef = new AtomicReference<>(); 
第一個string: join的條件 List:維表中本條資料的 欄位名 欄位值 

以此條sql為例
insert into  MyResult
    select m.id,m.title,m.amount,s.tablename1
	from MyTable m  left join sideTable s on m.id=s.id ;

從streamAPI角度就是 MyTable流來了根據m.id的值去Map中查詢是否存在對應的List,如果存在則根據欄位名取出對應的值拼接到MyTable流中。

LRU: 主要是在SideAsyncOperator類中 主要方法getSideJoinDataStream()
 

    public static DataStream getSideJoinDataStream(DataStream inputStream, String sideType, String sqlRootDir, RowTypeInfo rowTypeInfo,  JoinInfo joinInfo,
                                            List<FieldInfo> outFieldInfoList, SideTableInfo sideTableInfo) throws Exception {
        AsyncReqRow asyncDbReq = loadAsyncReq(sideType, sqlRootDir, rowTypeInfo, joinInfo, outFieldInfoList, sideTableInfo);
        //TODO How much should be set for the degree of parallelism? Timeout? capacity settings?
        return AsyncDataStream.orderedWait(inputStream, asyncDbReq, 10000, TimeUnit.MILLISECONDS, asyncCapacity)
                .setParallelism(sideTableInfo.getParallelism());
    }

依然只看需要關注的類:

可以看到這裡是用的非同步IO查詢,這裡的查詢是根據on後的條件 ,還是上面的邏輯程式碼 傳入m.id=3  此時就會到資料庫中查詢s.id=3的資料 快取到Cache<String, CacheObj> cache中 String是存入的值 如 3,CacheObj= new CacheObj(type, content)  type為列舉欄位MissVal(為查詢到資料),SingleLine(查詢的資料只會有一條(1對1)),MultiLine(查詢的資料有多條(1對多)) 。content為Object,如果是MultiLine 則表明content中需要存入多個資料。
快取時間:
 

 cache = CacheBuilder.newBuilder()
                .maximumSize(sideTableInfo.getCacheSize())
                .expireAfterWrite(sideTableInfo.getCacheTimeout(), TimeUnit.MILLISECONDS)
                .build();

在初始化Cache<String, CacheObj> cache時已經決定了快取的大小和時間。
從streamAPI角度就是 MyTable流來了根據m.id的值去資料庫中查詢,如果存在放入SingleLine或MultiLine,不存在則放入MissVal。然後快取起來,這裡呼叫的是非同步IO查詢。當有重複的key到來時就直接從快取中獲取資料往下傳送。

相關文章