spring-cloud-stream
spring-cloud-stream copied to clipboard
Enable Kafka Streams binder for Graal native compilation
@sobychacko commented on Tue Apr 27 2021
@sabbyanandan commented on Tue May 04 2021
Verification on the KTable is still pending.
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
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 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.
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 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.
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.
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
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 .
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
@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. 🙏🏽
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?
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.
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.
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.
"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.
- 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.
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.
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?
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 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?
@sdeleuze was that directed to myself?
@pdebuitlear Not specifically
@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.
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 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 Sorry to bother you, but is there any ETA or progress on this?
We are targeting this as part of the RC1
release scheduled for the end of this month.
The basic support for enabling Kafka Streams binder for native applications is in place. cc @rob-64 @0xabadea @andrashatvani
@sobychacko is there a snapshot repo where this is published?
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.
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