Flink 1.10.1在最大并行度为1时表现不同

时间:2020-06-24 21:08:05

标签: apache-flink flink-streaming complex-event-processing flink-cep

首先,我已经在这里找到了这个问题:flink program behaves differently in parallelism,看起来我现在正面临着同样的问题,但是我认为我的情况中确实需要CEP,因为我有很多每小时要分析属于不同用户密钥的1.000.000条记录。

因此,当我使用并行性1运行cep时,即使对于不同的用户键,一切都可以正常工作,但是有点慢,因为flink需要在单个线程中逐个用户分析用户,并且此操作需要足够快才能识别某种模式然后在不到1分钟的时间内发送通知,这就是为什么我需要多个并行线程的原因。

就我而言,我正在与RichFlatMapFunction一起使用,以保留前一个模式来识别下一个模式,然后发送通知,这是我的代码:

final DataStream<EventPush> eventsStream = RabbitMQConnector.eventStreamObject(env)
                .flatMap(new RabbitMQPushConsumer())
                .keyBy(k -> k.id);

private static SingleOutputStreamOperator<String> getPushToSend(KeyedStream<EventPush, String> stream) {
        return stream.flatMap(new WebPushFlatMapFunction())
                .map(x -> new ObjectMapper().writeValueAsString(x));
    }

/*the code below belongs to WebPushFlatMapFunction class, which is the RichFlatMapFunction using ValueState*/

 private boolean inTime(long start, long end) {
        final long difference = (end > start) ? (end - start) : (start - end);
        long time_frame = 120000L;
        return difference > 0 && time_frame >= difference;
    }

    @Override
    public void flatMap(EventPush value, Collector<EventPush> out) {
        final String pageName= value.pageName.trim();
        Tuple4<String, String, Long, Timestamp> prev;
        try {
            prev = previous.value();
            if (b_pageName.equalsIgnoreCase(pattern)) {
                LOG.info("umid " + value.idsUmid + " match (" + pattern + ") at: " + value.timestamp);
                previous.update(new Tuple4<>(value.idsUmid, pageName, value.timestamp.getTime(), value.timestamp));
            }
            if (prev != null) {
                if (inTime(value.timestamp.getTime(), prev.f2)) {
                    if ((prev.f1 != null && !prev.f1.equals("")) && prev.f1.equals(full_pattern) && pageName.equals(home) && prev.f3.before(value.timestamp)) {
                        if (PropertyFileReader.isWebPushLoggerActivated())
                            LOG.info("umid " + value.idsUmid + " match (" + home + ")" + "triggered at: " + value.timestamp);
                        prev.f1 = "";
                        out.collect(value);
                    }
                    if ((prev.f1 != null && !prev.f1.equals("")) && prev.f1.equals(pattern) && pageName.equals(full_pattern) && prev.f3.before(value.timestamp)) {
                        LOG.info("umid " + value.idsUmid + " match (" + full_pattern + ") at: " + value.timestamp);
                        prev.f3 = value.timestamp;
                        prev.f1 = pageName;
                        previous.update(prev);
                    }
                }
            }
        } catch (IOException e) {
            CatchHandler.generalCatchHandler(e);
        }
    }

使用并行度1,我得到正确的顺序:1、2、3。不仅如此,我还可以在一个线程中接收1个线程,从另一个线程中接收3个线程,因为所有线程都属于同一个用户密钥,并且这3个状态将被划分在不同的线程中。 我的问题:是否可以通过更多的并行性来做到这一点? 此致。

2 个答案:

答案 0 :(得分:0)

听起来您想将每个用户的所有分析都放在一起,但同时对不同用户执行分析。这样做的方法是通过userId键入流。这确实意味着对于单个用户,他们的事件由单个(非并行)管道处理。

如果速度太慢,则可能需要采取一些措施来加快速度。通常,最能帮助您的事情包括:更高效的序列化,进行预聚合或增量聚合,删除密钥或重新平衡以及实现对象重用。

答案 1 :(得分:0)

我发现问题出在后端,该问题是将相同的userId分配给不同的用户(不知道怎么回事,但是正在发生,不是flink),这就是为什么模式永远不匹配的原因,因为不同的用户具有相同userId且以不同顺序发送事件的事件在同一子任务中处理,它们在末尾合并,例如,来自user1的event1可以出现在来自user2的event2之后。问候