Canal+Disruptor集成到Springboot

  1. 本文主要目的是實現Canal+disruptor+springboot,訂閱mysql binlog日誌,實現數據同步,比如緩存,ES等。
    DEMO項目Github地址

  2. 組件簡介:
    Canal-阿里巴巴mysql數據庫binlog的增量訂閱&消費組件
    Disruptor-開源的併發框架,能夠在無鎖的情況下實現網絡的Queue併發操作

  3. 使用方式:
    Canal的服務端搭建參考
    Disruptor+Canal異步操作參考,業務集成時在DisruptorServiceImpl服務中實現自己的業務邏輯即可,代碼片段:

    public void execute(TableData tableData)
    {
        if (log.isDebugEnabled())
        {
            log.debug("接受數據更新請求,更新表名:{},更新的主鍵爲:{}", tableData.getTableName(), tableData.getId());
        }
        if (null != tableData)
        {
            //業務處理 TODO
        }
    }

CanalClientService中定製自己需要的binlog事件處理,代碼片段:

 private void processData(List<CanalEntry.Entry> entrys)
    {
        if (log.isDebugEnabled())
        {
            log.debug("接收到需要處理數據,總數量:{}", entrys.size());
        }

        List<TableData> tableDataList = new ArrayList<>(entrys.size());
        // 表名
        String tableName;
        TableData tableData;
        CanalEntry.RowChange rowChange;
        for (CanalEntry.Entry entry : entrys)
        {
            // 事物數據不處理
            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN
                    || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND)
            {
                continue;
            }

            if (entry.getEntryType() != CanalEntry.EntryType.ROWDATA)
            {
                continue;
            }

            //獲取表名
            tableName = entry.getHeader().getTableName();

            //僅處理部分表接口數據
            if (tableNames.contains(tableName))
            {
                try
                {
                    rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
                    // RowData --具體insert/update/delete的變更數據,可爲多條,1個binlog event事件可對應多條變更,比如批處理
                    for (CanalEntry.RowData rowData : rowChange.getRowDatasList())
                    {
                        switch (rowChange.getEventType())
                        {
                            //當前僅處理Insert和更新數據
                            case INSERT:
                            case UPDATE:
                                tableData = new TableData();
                                tableData.setTableName(tableName);
                                tableData.setId(parseKey(rowData.getAfterColumnsList()));
                                tableDataList.add(tableData);
                                break;
                            default:
                                break;
                        }
                    }
                }
                catch (Exception e)
                {
                    log.error("當前行數據解析錯誤:", e);
                }
            }
        }
        if (CollectionUtil.isNotEmpty(tableDataList))
        {
            //發送數據到異步隊列框架
            disruptorProducer.send(tableDataList);
        }
        if (log.isDebugEnabled())
        {
            log.debug("接收到Mysql更新數據,總數量:{}", tableDataList.size());
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章