Flink实时电商数仓之旁路缓存

撤回流的处理

撤回流是指流式处理过程中,两表join过程中的数据是一条一条跑过来的,即原本可以join到一起的数据在刚开始可能并没有join上。

  • 撤回流的格式:
  • 解决方案
    • 定时器:使用定时器定时10s(数据最大的时间差值),定时器触发时将状态中的数据发送过来
    • 如果重复计算这些数据,如何保持结果正确即可;通过每次度量值修改为当次度量值 - 上次度量值即可

异步IO

  • 减少等待的时间,充分利用已有的资源
  • 使用异步IO时,必须保证从头到尾都是异步的操作;即使用异步的连接器
c 复制代码
/**
     * 获取到 redis 的异步连接
     *
     * @return 异步链接对象
     */
    public static StatefulRedisConnection<String, String> getRedisAsyncConnection() {
        RedisClient redisClient = RedisClient.create("redis://hadoop102:6379/2");
        return redisClient.connect();
    }



    /**
     * 关闭 redis 的异步连接
     *
     * @param redisAsyncConn
     */
    public static void closeRedisAsyncConnection(StatefulRedisConnection<String, String> redisAsyncConn) {
        if (redisAsyncConn != null) {
            redisAsyncConn.close();
        }
    }

 /**
     * 获取到 Hbase 的异步连接
     *
     * @return 得到异步连接对象
     */
    public static AsyncConnection getHBaseAsyncConnection() {
        Configuration conf = new Configuration();
        conf.set("hbase.zookeeper.quorum", "hadoop102");
        conf.set("hbase.zookeeper.property.clientPort", "2181");
        try {
            return ConnectionFactory.createAsyncConnection(conf).get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭 hbase 异步连接
     *
     * @param asyncConn 异步连接
     */
    public static void closeAsyncHbaseConnection(AsyncConnection asyncConn) {
        if (asyncConn != null) {
            try {
                asyncConn.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

异步IO关联

  1. AsyncDataStream.unorderedWait(异步核心逻辑, 60, TimeUnit.SECONDS) 异步关联维度表
  2. CompletableFuture.supplyAsync(new Supplier<>(){ 异步访问读取Redis中的数据 }),返回的数据类型是Future类型
    • 先拼写访问的redisKey
    • 获取到dimSkuInfoFuture期货
    • 使用dimSkuInfoFuture.get()获取异步结果
  3. thenApplyAsync(new Function<>()), 旁路缓存判断,判断是否在redis中读取到相关数据,如果没有读取到,需要访问HBase.
  4. 需要重写HBase的getCells方法,改为getAsyncCells方法
    • 连接更换为异步连接
    • Future类型数据需要再get()方法获取具体的值
    • 无需关闭连接
  5. 将从HBase读取的数据保存到redis, redisAsyncConnection.async().setex(redisKey,24*60*60,dimJsonObj.toJSONString());

异步维度关联封装

  1. 继承RichAsyncFunction<TradeSkuOrderBean, TradeSkuOrderBean>接口
  2. 将表名和rowkey拼接的方法抽象化,让方法调用者自己传进来
  3. 封装join方法, join(TradeSkuOrderBean input, JSONOjbect dim); join方法里面填写度量值的聚合逻辑
  4. 将抽象方法和具体方法分离,把抽象方法放到接口中,在实现该接口
  5. TradeSkuOrderBean类改为泛型方法T
java 复制代码
public abstract class DimAsyncFunction<T> extends RichAsyncFunction<T, T>
implements DimJoinFunction<T>{

    StatefulRedisConnection<String, String> redisAsyncConnection;
    AsyncConnection hBaseAsyncConnection;
    String tableName;


    @Override
    public void open(Configuration parameters) throws Exception {
        redisAsyncConnection = RedisUtil.getRedisAsyncConnection();
        hBaseAsyncConnection = HBaseUtil.getHBaseAsyncConnection();
    }

    @Override
    public void close() throws Exception {
        RedisUtil.closeRedisAsyncConnection(redisAsyncConnection);
        HBaseUtil.closeAsyncHbaseConnection(hBaseAsyncConnection);
    }

    @Override
    public void asyncInvoke(T input, ResultFuture<T> resultFuture) throws Exception {
        //java的异步编程方式
        String tableName = getTableName();
        String rowKey = getId(input);
        String redisKey = RedisUtil.getRedisKey(tableName, rowKey);
        CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {

                //第一步异步访问得到的数据

                RedisFuture<String> dimSkuInfoFuture = redisAsyncConnection.async().get(redisKey);
                String dimInfo = null;
                try {
                    dimInfo = dimSkuInfoFuture.get();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return dimInfo;
            }
        }).thenApplyAsync(new Function<String, JSONObject>() {
            @Override
            public JSONObject apply(String dimInfo) {
                JSONObject dimJsonObj = null;
                //旁路缓存判断
                if (dimInfo == null || dimInfo.isEmpty()) {
                    try {
                        //需要访问HBase
                        dimJsonObj = HBaseUtil.getAsyncCells(hBaseAsyncConnection, Constant.HBASE_NAMESPACE, tableName, rowKey);
                        //将读取的数据保存到redis
                        redisAsyncConnection.async().setex(redisKey, 24 * 60 * 60, dimJsonObj.toJSONString());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    //redis中存在缓存数据
                    dimJsonObj = JSONObject.parseObject(dimInfo);
                }
                return dimJsonObj;
            }
        }).thenAccept(new Consumer<JSONObject>() {
            public void accept(JSONObject dim) {
                //合并维度信息
                if (dim == null) {
                    //无法关联到维度信息
                    System.out.println("无法关联到当前的维度信息:" + tableName + ":" + rowKey);
                } else {
                    join(input,dim);
                }

                //返回结果
                resultFuture.complete(Collections.singletonList(input));
            }
        });
    }



}
相关推荐
材料苦逼不会梦到计算机白富美3 小时前
golang分布式缓存项目 Day 1
分布式·缓存·golang
拓端研究室TRL3 小时前
【梯度提升专题】XGBoost、Adaboost、CatBoost预测合集:抗乳腺癌药物优化、信贷风控、比特币应用|附数据代码...
大数据
黄焖鸡能干四碗3 小时前
信息化运维方案,实施方案,开发方案,信息中心安全运维资料(软件资料word)
大数据·人工智能·软件需求·设计规范·规格说明书
Java 第一深情3 小时前
高性能分布式缓存Redis-数据管理与性能提升之道
redis·分布式·缓存
编码小袁3 小时前
探索数据科学与大数据技术专业本科生的广阔就业前景
大数据
HBryce244 小时前
缓存-基础概念
java·缓存
WeeJot嵌入式4 小时前
大数据治理:确保数据的可持续性和价值
大数据
zmd-zk5 小时前
kafka+zookeeper的搭建
大数据·分布式·zookeeper·中间件·kafka
激流丶5 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
测试界的酸菜鱼5 小时前
Python 大数据展示屏实例
大数据·开发语言·python