spring-cloud-stream icon indicating copy to clipboard operation
spring-cloud-stream copied to clipboard

Enable Kafka Streams binder for Graal native compilation

Open sobychacko opened this issue 2 years ago • 3 comments

@sobychacko commented on Tue Apr 27 2021


@sabbyanandan commented on Tue May 04 2021

Verification on the KTable is still pending.

sobychacko avatar Mar 30 '22 15:03 sobychacko

Most likely this is blocked by the JVM reachability for the state store JNI as described in https://github.com/spring-projects-experimental/spring-native/issues/680

onobc avatar Jul 28 '22 15:07 onobc

My tests on https://github.com/spring-projects/spring-aot-smoke-tests/tree/main/cloud-stream-kafka (confirmed by the CI) seems to indicate it is now working, should this issue be updated accordingly?

sdeleuze avatar Sep 23 '22 08:09 sdeleuze

@sdeleuze that AOT smoke test only covers the Kafka binder, not the KafkaStreams binder that this is referring to (naming... they sound very much like "the thing").

Once this issue is addressed (or it is no longer an issue) then another AOT smoke test should be added to cover it as well.

onobc avatar Sep 23 '22 13:09 onobc

Support for Kafka Streams doesn't work out of the box, some additional hints are needed. See this project for a working example. There are also hints in that project for the Confluent schema registry and the Confluent serializers.

pdebuitlear avatar Jan 05 '23 19:01 pdebuitlear

@pdebuitlear We haven't addressed native changes for the Kafka Streams binder yet, but we will do it as part of one of the upcoming 4.x releases. Thanks for sharing the project, as that will be a good reference.

sobychacko avatar Jan 05 '23 20:01 sobychacko

Looking to that project, @pdebuitlear , I would say that I don't see anything Spring Cloud Stream related or even Spring at all. It really would be better to have Native images support directly from those libs, so any target implementation would benefit from a common place, not just this Spring Cloud Stream Kafka Streams Binder. So, I would suggest to consider raising improvement tickets in respective Kafka Streams and Confluent Platform projects respectively.

artembilan avatar Jan 05 '23 20:01 artembilan

Looking to that project, @pdebuitlear , I would say that I don't see anything Spring Cloud Stream related or even Spring at all. It really would be better to have Native images support directly from those libs, so any target implementation would benefit from a common place, not just this Spring Cloud Stream Kafka Streams Binder. So, I would suggest to consider raising improvement tickets in respective Kafka Streams and Confluent Platform projects respectively.

Not even these? https://github.com/pdebuitlear/kstreams-demo/blob/main/src/main/java/com/example/demo/config/hints/KafkaStreamsHints.java

pdebuitlear avatar Jan 05 '23 20:01 pdebuitlear

Of course no, because those types and resources are exactly from Kafka Streams project. And I believe that we have to expose them even if we just try to build plain Kafka Streams application, even without Spring for Apache Kafka .

artembilan avatar Jan 05 '23 20:01 artembilan

Spring for Apache Kafka added a few hints for basic Kafka, and Kafka Streams, support, but this was for expediency, to prove out the core project can support native images; it is impractical for Spring projects to maintain ongoing, extensive, hints for all dependencies.

There are some sample smoke tests for the basic hints. https://github.com/spring-projects/spring-aot-smoke-tests/tree/main/integration

garyrussell avatar Jan 05 '23 20:01 garyrussell

@sobychacko @artembilan @garyrussell @olegz: Many thanks for continuing to evolve the binders and making Kafka integration easier for Java developers. The developer community appreciates your time and commitment. 🙏🏽

sabbyanandan avatar Jan 05 '23 20:01 sabbyanandan

Spring for Apache Kafka added a few hints for basic Kafka, and Kafka Streams, support, but this was for expediency, to prove out the core project can support native images; it is impractical for Spring projects to maintain ongoing, extensive, hints for all dependencies.

There are some sample smoke tests for the basic hints. https://github.com/spring-projects/spring-aot-smoke-tests/tree/main/integration

That's a fair point, thanks. Does that leave the Spring stack gapped in comparison with other frameworks?

pdebuitlear avatar Jan 05 '23 21:01 pdebuitlear

I don’t find it as a correct comparison: such a native hint really has to be in that library, not any framework. This way all the frameworks and any library consumers would benefit. Not sure why you don’t see it as so obvious reasonable solution. Native images is really not Spring feature, so exposing hints for third parties is doubtful work for Spring. We cannot judge other framework solutions, but it is not so convenient to keep hints for common libs just in Spring.

artembilan avatar Jan 05 '23 21:01 artembilan

I don’t find it as a correct comparison: such a native hint really has to be in that library, not any framework. This way all the frameworks and any library consumers would benefit. Not sure why you don’t see it as so obvious reasonable solution. Native images is really not Spring feature, so exposing hints for third parties is doubtful work for Spring. We cannot judge other framework solutions, but it is not so convenient to keep hints for common libs just in Spring.

Ok forget the Confluent stuff for the moment, I can create a project in Quarkus for Kafka Streams and it will add hints for the Apache Kafka classes and dependent RocksDB .so libs. That does not work with Spring Native/Kafka/Aot code currently.

pdebuitlear avatar Jan 05 '23 22:01 pdebuitlear

What if I don’t want Quarkus and just want to build native app just with plain Kafka Streams? Why would I always go for Quarkus just because it exposes hints for RocksDB?

I find your push to us as counterproductive: the native hint is really has to be exposed in that library which is responsible for those types. Is it Quarkus who maintains RocksDB? Why similar native hints have to be in Quarkus and Spring? Why just Apache Kafka cannot provide for us all a single solution for types it supports? I just really think here about broader Apache Kafka and GraalVM community, not just those who make their applications based on Spring.

artembilan avatar Jan 05 '23 22:01 artembilan

"Kafka Streams uses RocksDB as the default storage engine for persistent stores" It's a dependent jar of Apache Kafka. It's just a bit strange that some functionality in Apache Kafka would have 'hints' and some wouldn't. At least document it, if your going to make life difficult for your user base.

pdebuitlear avatar Jan 05 '23 22:01 pdebuitlear

  • Initial intent should be to contibute hints and related tests to the various libraries.
  • If they refuse for some reasons, remaining non Spring related hints should be contributed to https://github.com/oracle/graalvm-reachability-metadata, where Spring is the number one contributor by far.
  • Spring related hints should live in respective Spring projects.

Happy to help on contributions on https://github.com/oracle/graalvm-reachability-metadata if needed.

sdeleuze avatar Jan 06 '23 07:01 sdeleuze

We still are planning to look into this overarching theme of ensuring that Kafka Streams binder-based apps are AOT/native compatible in the same way that we did with the regular Kafka binder. Since Spring for Apache Kafka already verified the core components for Kafka Streams, I would like to provide some essential support from the binder side. We didn't get to do this verification in the 4.0.0 timeline. As a first step, I was thinking of adding any third-party hints on our side (we did that for Pulsar recently) and, as things evolve, contributing back to the respective libraries.

sobychacko avatar Jan 06 '23 14:01 sobychacko

Could you try to contribute the third party bits to https://github.com/oracle/graalvm-reachability-metadata like we do for the rest of the Spring portfolio?

sdeleuze avatar Jan 09 '23 11:01 sdeleuze

Could you try to contribute the third party bits to https://github.com/oracle/graalvm-reachability-metadata like we do for the rest of the Spring portfolio?

@sdeleuze was that directed to myself?

pdebuitlear avatar Jan 31 '23 11:01 pdebuitlear

@pdebuitlear We can look into this as a start. Could you please describe your use case once again? Are you trying to use the Kafka Streams binder in Spring Cloud Stream with graalvm? Is that where you run into the issues?

sobychacko avatar Jan 31 '23 14:01 sobychacko

@sdeleuze was that directed to myself?

@pdebuitlear Not specifically

sdeleuze avatar Feb 02 '23 14:02 sdeleuze

@sobychacko My attempt of running a Spring Cloud Stream Kafka Streams app as native/aot resulted in the following error:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kafkaStreamsFunctionBeanPostProcessor': class org.springframework.beans.factory.support.RootBeanDefinition cannot be cast to class org.springframework.beans.factory.annotation.AnnotatedBeanDefinition (org.springframework.beans.factory.support.RootBeanDefinition and org.springframework.beans.factory.annotation.AnnotatedBeanDefinition are in unnamed module of loader 'app')
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1751)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325)
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334)
	... 21 common frames omitted
Caused by: java.lang.ClassCastException: class org.springframework.beans.factory.support.RootBeanDefinition cannot be cast to class org.springframework.beans.factory.annotation.AnnotatedBeanDefinition (org.springframework.beans.factory.support.RootBeanDefinition and org.springframework.beans.factory.annotation.AnnotatedBeanDefinition are in unnamed module of loader 'app')
	at org.springframework.cloud.stream.binder.kafka.streams.function.KafkaStreamsFunctionBeanPostProcessor.extractResolvableTypes(KafkaStreamsFunctionBeanPostProcessor.java:174)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at org.springframework.cloud.stream.binder.kafka.streams.function.KafkaStreamsFunctionBeanPostProcessor.afterPropertiesSet(KafkaStreamsFunctionBeanPostProcessor.java:104)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747)
	... 31 common frames omitted

This app has only one stream function written in Kotlin 1.8 with Spring Boot 3.0.2 and Spring Cloud 2022.0.1.

andrashatvani avatar Feb 16 '23 12:02 andrashatvani

I just ran into this error too. It seems to me this is not a case of missing hints. At runtime, the beans (resulting from the AOT processing) are built from RootBeanDefinition-s, which does not implement AnnotatedBeanDefinition.

0xabadea avatar Aug 18 '23 12:08 0xabadea

@0xabadea As soon as the Spring One conference is over next week, this issue will be a priority for us, and we will work on it. Please stay tuned.

sobychacko avatar Aug 18 '23 14:08 sobychacko

@sobychacko Sorry to bother you, but is there any ETA or progress on this?

rob-64 avatar Oct 05 '23 18:10 rob-64

We are targeting this as part of the RC1 release scheduled for the end of this month.

sobychacko avatar Oct 05 '23 20:10 sobychacko

The basic support for enabling Kafka Streams binder for native applications is in place. cc @rob-64 @0xabadea @andrashatvani

sobychacko avatar Oct 25 '23 13:10 sobychacko

@sobychacko is there a snapshot repo where this is published?

rob-64 avatar Oct 29 '23 16:10 rob-64

Hi @rob-64

You can find snapshots on repo.spring.io/snapshot (ex: https://repo.spring.io/ui/native/snapshot/org/springframework/cloud/spring-cloud-stream-binder-kafka-streams/4.1.0-SNAPSHOT/)

Easiest way to setup for this is to go to start.spring.io and choose a snapshot Boot version. The resulting build (Maven or Gradle) will be setup accordingly.

onobc avatar Oct 29 '23 17:10 onobc

Hi, I try with:

  • spring-boot-starter-parent : 3.2.0-RC1 and 3.0.1
  • https://github.com/pdebuitlear/kstreams-demo/blob/main/src/main/java/com/example/demo/config/hints/KafkaStreamsHints.java
  • spring-cloud-stream-binder-kafka:4.1.0-SNAPSHOT

when run a exe:

`10:40:59.658 ERROR --- [ main] o.s.boot.SpringApplication : Application run failed

java.lang.NoSuchMethodError: java.lang.invoke.MethodHandle.get() at org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration__BeanDefinitions$JettyWebSocketConfiguration.getJettyWebSocketConfigurationBeanDefinition(WebSocketServletAutoConfiguration__BeanDefinitions.java:30) ` exists any solution?

tnx

marcoberri avatar Nov 03 '23 10:11 marcoberri