espertechinc / esper

Esper Complex Event Processing, Streaming SQL and Event Series Analysis
GNU General Public License v2.0
841 stars 259 forks source link

Improve Compile and Deploy efficiency in Esper 8+ #249

Closed subrata304 closed 3 years ago

subrata304 commented 3 years ago

Currently we are using Esper V5 in our production system and it has more than 200k+ EPL statements.

We wanted to upgrade our esper version and hence we are trying to do a POC and load test on the same but seeing some big difference w.r.t loading time of EPL statements.

We are using an executor service to load all statements in Esper runtime while server starts. Exact similar configurations are used(w.r.t. inbound thread pool param and everything else) in both version i.e. V5 and V8.7 but loading time in V8.7 is much more than earlier version.

In load test we found out it is taking more than 20 minutes to load 3500+ statements in esper V8.7 whereas in esper V5 it took only 17 seconds. Imagine what would happen if we run this in our prod system where we have 200k+ epl statements which are currently getting loaded within 5 minutes(using Esper V5)

Moreover while debugging more we found that compile and deploy method is taking more time among everything else. compile method is taking 30 milliseconds to 4 seconds(approx.) for each statements and similarly deploy method also taking more time.

Avg compile time - 293.88 ms Avg Deploy time - 136.92 ms Avg loading time per EPL statement - 430.80 ms

Below is the sample code which we are using to compile and deploy EPL statements..

public EPDeployment compileDeploy(EPRuntime runtime, final String epl, final String deploymentId,final Subs subsc) { try { // Obtain a copy of the engine configuration Configuration configuration = runtime.getConfigurationDeepCopy();

        // Build compiler arguments
        CompilerArguments args = new CompilerArguments(configuration);

        // Make the existing EPL objects available to the compiler
        args.getPath().add(runtime.getRuntimePath());

        // Compile
        EPCompiled compiled = EPCompilerProvider.getCompiler().compile(epl, args); // Response time is very high

        DeploymentOptions options = new DeploymentOptions();
        options.setDeploymentId(deploymentId);
        options.setStatementNameRuntime(new StatementNameRuntimeOption() {
            public String getStatementName(StatementNameRuntimeContext env) {
                return SpotlightConstants.DEFAULT_STATEMENT_NAME;
            }
        });
       options.setStatementUserObjectRuntime(new StatementUserObjectRuntimeOption() {
            public Object getUserObject(StatementUserObjectRuntimeContext env) {
              return subsc;
            }
          });
        return runtime.getDeploymentService().deploy(compiled, options); // Response time is high
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
bernhardttom commented 3 years ago

The compile step can be done once and EPCompiled saved with EPCompiledIOUtil or serialize. Deploy takes around 2.5 milliseconds for me.

        EPCompiled compiled = env.compile("select * from SupportBean");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            env.deploy(compiled);
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
subrata304 commented 3 years ago

Hello @bernhardttom,

Couple of things to clear out.

  1. We used the compileDeploy() method mentioned in the Esper documentation to compile and deploy statements. But I see you mentioned something like env.compile("EPL Statements"), Could you please provide the whole code for this? Looks like you are doing it in different way.

  2. Secondly our EPL statements are complex in nature where we have multiple filter criteria with all sorts of operator like '=', '!=', '>', '<', '>=','<=', 'OR', 'AND', 'in', 'not in' and even complex regex expression as well. Moreover all these kind of EPL statements are getting loaded in memory within few seconds with Esper V5 but with Esper V8 it's taking huge time as I have mentioned.

  3. Lastly, we have very frequent update to this EPL statements and also we need to remove/add these statements from memory frequently to support some business logic.

All of these are working fine in Esper V5 and even in EsperV8 rate of matching EPL statements is actually gone high but we are facing problem with loading time of the statements.

E.g. -

  1. 'select * from Event( ( eventType = toUUID(“bc6018d6-6376-4f22-ad39-3ad5bce49c9e”) ) and ( ( property(‘’messagingConfigurationName’’).value = “config1" ) and ( property(‘’queueName’’).value = “TEST.QUEUE” ) and ( ( toNumber(property(‘’currentDepth’’).value) >= 1000 ) or ( toNumber(property(‘’messageAge’’).value) >= 10 ) ) ) )'

Above statement took 1186 ms to compile and 102 ms to deploy

  1. ’select from Event( ( eventType = toUUID(“c7df6e15-b411-4e36-8b69-900321ee4c91") ) and ( ( property(‘’Tag’’).value regexp “.Kubernetes]app:status.” ) and ( property(‘’Tag’’).value regexp “.Namespace:wnleld.” ) and ( property(‘’Tag’’).value regexp “.EnvType:dev.” ) and ( property(‘’Tag’’).value regexp “.InfrastructureType:k8s.*” ) ) )'

Above statement took 1214 ms to compile and 89 ms to deploy

Could you please point us whether we are doing this in right way or not, keeping in mind we have 200k+ statements to load in memory at server start?