java, apache pulsar Topic partition - java

If I have a topic called var test = "test"
and I create a bean:
#Bean(name = "test")
public Producer<Test> testProducer(PulsarClient pulsarClient){
return pulsarClient.newProducer()
.topic(test)
.create();
}
The topic is created I want to partition, how?

To create a topic with partitions you can either configure the following settings for the Pulsar Broker (if you are relying on automatic topic creation)
allowAutoTopicCreationType = partitioned
defaultNumPartitions = <N>
Alternatively you can use the Pulsar Admin and use createPartitionedTopic
https://github.com/apache/pulsar/blob/a165bda1d03e370f5efe1173134fb94e12b584b5/pulsar-client-admin-api/src/main/java/org/apache/pulsar/client/admin/Topics.java#L473-L475
However once a topic has been created (I assume non-partitioned) then there is no way to make it partitioned. It has to be partitioned at topic creation time.

Related

Consume 2 topics but process only one topic which is enabled

For our application we are writing the smae messages to 2 different Kafka Brokers with 2 different topics, now at the consumer part I have to consume both the topics and process only one topic that is enabled in spring boot property file.
How I can do it using spring boot and KafkaListner??
You can configure this simply by :
#KafkaListener(topics = { "${spring.kafka.topic1}", "${spring.kafka.topic2}" })
Now if you want to consume both but process one and discard the other you can use keys in the messages and create the key accordingly on both topics
Ref:
Java consumer API : ConsumerRecord#key()

Connecting to multiple clusters spring kafka

I would like to consume messages from one kafka cluster and publish to another kafka cluster. Would like to know how to configure this using spring-kafka?
Simply configure the consumer and producer factories with different bootstrap.servers properties.
If you are using Spring Boot, see
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#spring.kafka.consumer.bootstrap-servers
and
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#spring.kafka.producer.bootstrap-servers
If you are creating your own factory #Beans, set the properties there.
https://docs.spring.io/spring-kafka/docs/current/reference/html/#connecting
you can use spring cloud stream kafka binders.
create two stream one for consume and one for producing.
for consumer
public interface InputStreamExample{
String INPUT = "consumer-in";
#Input(INPUT)
MessageChannel readFromKafka();
}
for producer
public interface ProducerStreamExample{
String OUTPUT = "produce-out";
#Output(OUTPUT)
MessageChannel produceToKafka();
}
for consuming message use:
#StreamListener(value = ItemStream.INPUT)
public void processMessage(){
/*
code goes here
*/
}
for producing
//here producerStreamExample is instance of ProducerStreamExample
producerStreamExample.produceToKafka().send(/*message goes here*/);
Now configure consumer and producer cluster using binder, you can use consumer-in for consumer cluster and produce-out for producing cluster.
properties file
spring.cloud.stream.binders.kafka-a.environment.spring.cloud.stream.kafka.binder.brokers:<consumer cluster>
#other properties for this binders
#bind kafka-a to consumer-in
spring.cloud.stream.bindings.consumer-in.binder=kafka-a #kafka-a binding to consumer-in
#similary other properties of consumer-in, like
spring.cloud.stream.bindings.consumer-in.destination=<topic>
spring.cloud.stream.bindings.consumer-in.group=<consumer group>
#now configure cluster to produce
spring.cloud.stream.binders.kafka-b.environment.spring.cloud.stream.kafka.binder.brokers:<cluster where to produce>
spring.cloud.stream.bindings.produce-out.binder=kafka-b #here kafka-b, binding to produce-out
#similary you can do other configuration like topic
spring.cloud.stream.bindings.produce-out.destination=<topic>
Refer to this for more configuration: https://cloud.spring.io/spring-cloud-stream-binder-kafka/spring-cloud-stream-binder-kafka.html

Consume messages from RabbitMQ queue using spring cloud stream 3.0+

I have a Producer producing messages in a RabbitMQ queue by using a direct exchange.
queue name: TEMP_QUEUE,
exchange name: TEMP_DIRECT_EXCHANGE
Producing to this queue is easy since on my producer application I use Spring AMQP which I am familiar with.
On my Consumer application, I need to use Spring cloud stream version 3.0+.
I want to avoid using legacy annotations like #EnableBinding, #StreamListener because they are about to be depracated.
Legacy code for my application would look like that :
#EnableBinding(Bindings.class)
public class TempConsumer {
#StreamListener(target = "TEMP_QUEUE")
public void consumeFromTempQueue(MyObject object) {
// do stuff with the object
}
}
public interface Bindings {
#Input("TEMP_QUEUE")
SubscribableChannel myInputBinding();
}
From their docs I have found out I can do something like that
#Bean
public Consumer<MyObject> consumeFromTempQueue() {
return obj -> {
// do stuff with the object
};
}
It is not clear to me how do I specify that this bean will consume from TEMP_QUEUE? Also what if I want to consume from multiple queues?
See Consuming from Existing Queues/Exchanges.
You can consume from multiple queues with
spring.cloud.stream.bindings.consumeFromTempQueue-in-0.destination=q1,q2,q3
spring.cloud.stream.bindings.consumer.multiplex=true
Without multiplex you'll get 3 bindings; with multiplex, you'll get 1 listener container listening to multiple queues.
You need to use the application.yml to bind your bean.
spring.cloud.stream:
function.definition: consumeFromTempQueue
You can use this configuration to configure source, process and sink as well. In your case you are just using a source.
You can read this post for more information.

Can I use multiple elastic search hosts in Spring Bean configuration for multiple elastic search indexes

I have a Java API to insert documents to three elastic indexes and it is working. I want to change one index's host in API. Normally, EsConfig file and ElasticSearchTemplate code is ;
public class EsConfig {
#Value("${elasticsearch.host}")
private String EsHost;
#Value("${elasticsearch.port}")
private int EsPort;
#Value("${elasticsearch.clustername}")
private String EsClusterName;
#Bean
public Client client() throws Exception {
Settings settings = Settings.builder()
.put("cluster.name", EsClusterName)
//.put("index.max_result_window", 4000000)
.build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new
TransportAddress(InetAddress.getByName(EsHost), EsPort));
return client;
}
#Bean
public ElasticsearchTemplate elasticsearchTemplate() throws Exception {
ElasticsearchTemplate elasticsearchTemplate = new ElasticsearchTemplate(client());
return elasticsearchTemplate;
}
}
I want to configure this structure to use two hosts together. Is it possible in this structure or should I completely change and remove singleton bean structure?
Elasticsearch client api allows you to configure multiple host names in the below fashion but unfortunately, they do not work as expected.
According to this LINK,
The TransportClient connects remotely to an Elasticsearch cluster
using the transport module. It does not join the cluster, but simply
gets one or more initial transport addresses and communicates with
them in round robin fashion on each action (though most actions will
probably be "two hop" operations).
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
.addTransportAddress(new TransportAddress(InetAddress.getByName("host1"), 9300))
.addTransportAddress(new TransportAddress(InetAddress.getByName("host2"), 9300));
What you can do perhaps is go ahead and implement a Spring Boot concept of Profiles where you can create multiple application.properties. Below is one of the ways to achieve this.
If I have two different hosts/environments for e.g. dev and prod, I would end up creating three application properties file (Two for the environments, one properties which would mention which environment you'd want to select).
application-dev.properties
elasticsearch.clustername = mycluster_name
elasticsearch.host = mydev.abc.com <-- Configure the name of host 1
elasticsearch.port = 9300
application-prod.properties
elasticsearch.clustername = mycluster_name_2
elasticsearch.host = myprod.abc.com <-- Configure the name of host 2
elasticsearch.port = 9300
application.properties
spring.profiles.active=dev <-- Configure which of the above properties do you want to start application with
Now when you run the application as spring boot, it would end up starting the dev environment.
Note that I'm assuming that both these nodes are in different clusters and not part of the same cluster. The reason I specify this is because, elasticsearch internally would go ahead and update the replica shards of other nodes if it receives a new/updated document. Being in same cluster, it wouldn't matter which host in a cluster you are pointing to.
Let me know if this is what you are looking for.

ActiveMQ generating queues which don't exists

I have a problem with using ActiveMQ in Spring application.
I have a few environments on separate machines. On each machine I had one ActiveMQ instance installed. Now, I realized that I can have only one ActiveMQ instance installed on one server, and few applications can use that ActiveMQ for sending messages. So, I must change queue names in order to have different queues for different environments ("queue.search.sandbox", "queue.search.production", ...).
After that change, now ActiveMQ is generating new queues, but also the old ones, although there is no such configuration for doing that.
I am using Java Spring application with Java configuration, not XML.
First, I create queueTemplate as a Spring bean:
#Bean
public JmsTemplate jmsAuditQueueTemplate() {
log.debug("ActiveMQConfiguration jmsAuditQueueTemplate");
JmsTemplate jmsTemplate = new JmsTemplate();
String queueName = "queue.audit.".concat(env.getProperty("activeMqBroker.queueName.suffix"));
jmsTemplate.setDefaultDestination(new ActiveMQQueue(queueName));
jmsTemplate.setConnectionFactory(connectionFactory());
return jmsTemplate;
}
Second, I create ActiveMQ Listener configuration:
#Bean
public DefaultMessageListenerContainer jmsAuditQueueListenerContainer() {
log.debug("ActiveMQConfiguration jmsAuditQueueListenerContainer");
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(connectionFactory);
String queueName = "queue.audit.".concat(env.getProperty("activeMqBroker.queueName.suffix"));
ActiveMQQueue activeMQ = new ActiveMQQueue(queueName);
dmlc.setDestination(activeMQ);
dmlc.setRecoveryInterval(30000);
dmlc.setSessionTransacted(true);
// To perform actual message processing
dmlc.setMessageListener(auditQueueListenerService);
dmlc.setConcurrentConsumers(10);
// ... more parameters that you might want to inject ...
return dmlc;
}
After building my application, as the result I have properly created queue with suffix ("queue.audit.sandbox"), but after some time ActiveMQ generates and the old version ("queue.audit").
Does someone knows how ActiveMQ is doing this? Thanks in advance.
There is probably still an entry in the index for the queue, so when ActiveMQ restarts it is displaying the queue. If you want to be certain about destinations, use startup destinations and disable auto-creation by denying the "admin" permission to the connecting user account in the authorization entry
After some time ActiveMQ just stopped creating queues that don't exist.
Now, we have expected behavior, without unnecessary queues.
Still I didn't found out what solved this problem, to be sincere...

Categories

Resources