2

I am a new user of chronicle queue and I wanna use a zero allocation strategy to read and write the objects from chronicle queue. I want to use a queue and a marshable implementation of bytes like a pojo class is the that some correct strategy? I did not found anything to help me. I try to do a instance of message class below for append and read the content from the queue. When i try to read with more than one thread I always get out of memory error.

public class Message implements BytesMarshallable{
    private byte[] text;
    private long timeStamp;
    
    public Message(){}

    //Getters and Setters
}

I tryed to read using tailer.readDocument when i got out of memory error with more than one thread

1 Answers1

1

Using byte[] requires you to allocate a new one every time the size changes. You can't change the size of a byte[].

Instead, I suggest using out Bytes class which can be resized without creating much garbage (only sometimes when it grows)

package run.chronicle.queue;

import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.wire.BytesInBinaryMarshallable;
import net.openhft.chronicle.wire.LongConversion;
import net.openhft.chronicle.wire.MilliTimestampLongConverter;

public class Message extends BytesInBinaryMarshallable {
    private final Bytes text = Bytes.allocateElasticOnHeap();

    @LongConversion(MilliTimestampLongConverter.class)
    private long timeStamp;

    //Getters and Setters


    public Bytes getText() {
        return text;
    }

    public void setText(CharSequence text) {
        this.text.clear().append(text);
    }

    public long getTimeStamp() {
        return timeStamp;
    }

    public void setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
    }
}

See this example https://github.com/OpenHFT/Chronicle-Queue-Demo/tree/master/messages-with-text

When run with a small heap -Xmx128m -XX:NewSize=96m -verbose:gc MessageMain you can see that millions of messages trigger no collections.

Read 10,000,000 of 10,000,000 messages in 7.990 seconds
Read 10,000,000 of 10,000,000 messages in 6.907 seconds
[main] INFO net.openhft.chronicle.bytes.MappedFile - Took 2 ms to add mapping for test-438402668456/metadata.cq4t
Read 10,000,000 of 10,000,000 messages in 6.836 seconds
[main] INFO net.openhft.chronicle.bytes.MappedFile - Took 2 ms to add mapping for test-445239126125/metadata.cq4t
Read 10,000,000 of 10,000,000 messages in 6.883 seconds
[main] INFO net.openhft.chronicle.bytes.MappedFile - Took 3 ms to add mapping for test-452122895277/metadata.cq4t
Read 10,000,000 of 10,000,000 messages in 7.013 seconds
Read 10,000,000 of 10,000,000 messages in 6.838 seconds
[main] INFO net.openhft.chronicle.bytes.MappedFile - Took 2 ms to add mapping for test-465974753213/metadata.cq4t
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Hi Peter, thanks for the help. The best performance is obtained in this example using Bytes, I mean I wanna avoid GC Runs as you mentioned and I have the maximum buffer size. With that i can for example get the best performance for read and writing in chronicle queue using BytesInBinaryMarshallable and a binary queue? – Domenico Schettini Filho Jan 25 '21 at 13:50
  • @DomenicoSchettiniFilho The `Bytes` will resize as needed, but you can provide a specific size to tune it. I am not sure what you question is, can you rephrase it? – Peter Lawrey Jan 25 '21 at 14:15
  • For sure Peter. I am trying to get the best performance to write and read from chronicle queue with zero gc if is possible or stay at minimum. My class as I describe has some text fields and primitives like the timestamp. As I have the max buffer size i can tune the gc possible not having resizing on bytes. Beyond that the performance for read/writing from queue is good one with this solution in your opinion? – Domenico Schettini Filho Jan 25 '21 at 14:37
  • @DomenicoSchettiniFilho You can see the overhead, in this case, is around 0·3 microseconds, there are slightly faster options but they are harder to work with so I would start with this. – Peter Lawrey Jan 25 '21 at 14:56
  • Nice Peter. If you have reference for faster options I will try as well. I would benchmark more options anyway even if it is harder. Thank you for the help. – Domenico Schettini Filho Jan 25 '21 at 15:48
  • @DomenicoSchettiniFilho The biggest overhead is your text, how long is the string, if you can encode it with say Base85 (see an example of an encoder above) you can combine a 10 character string into a long and cut latency further. – Peter Lawrey Jan 26 '21 at 09:44
  • Hi @PeterLawrey. Nice thanks you for the advice, maybe using this field as binary will help too. Beyond that strategy i could for example retrieving the values directly from memory could improve someway the latency? As you mention the great overhead in that solution is the text. I will work in an alternative. – Domenico Schettini Filho Jan 26 '21 at 12:51
  • @DomenicoSchettiniFilho You could look at Chronicle Values which supports accessing fixed length fields without having to read the whole object. – Peter Lawrey Jan 26 '21 at 18:25
  • Hi @PeterLawrey thanks for the tip. I check Chronicle Values and certainly is a good option to limit the size of fields. I have another question about write/read in chronicle queue exista a way to have multiple listeners and writers in different threads like events? I wanna have multiple readers that read only if a new write is done on the queue, but readers in different threads. This is possible? – Domenico Schettini Filho Jan 27 '21 at 14:00
  • @DomenicoSchettiniFilho you can have any number of readers/writers for the same queue. For a reader to check if there is anything to read it needs to poll the queue. – Peter Lawrey Jan 28 '21 at 08:14
  • In order to use multiple threads the best way is to use events like methodReader and methodWriter? And as We see the worst overhead used in that class is the text field, you mentioned to use Base85 before, but for example If I have long text (unfortunatelly not in binary form) using base 85 or even 64 it will improve the read and time writing but in the case of marshalliing and unmarshalling the fields. I will try to benchmark. Thanks Peter for your help. – Domenico Schettini Filho Jan 29 '21 at 11:44
  • @DomenicoSchettiniFilho Bytes is the best option for longer strings. – Peter Lawrey Jan 29 '21 at 12:00
  • Nice I am using Bytes @PeterLawrey. I refactor the class for this: `public class Message extends BytesInBinaryMarshallable { private final Bytes text; private long timeStamp; //Getters and Setters }` I don't use for now methodReader or methodWriter to write/read from queue. I am actually using readDocument and writeDocument. This way it is ok or exists a better option? – Domenico Schettini Filho Jan 29 '21 at 12:39
  • Hi @PeterLawrey have a way to read/write with more performance because in my tests i get as we talked the bottleneck for me is the text field, but i am looking for another options of reading and writing. Because right now i am using the following methods to read/write: readDocument and writeDocument. I am trying to paralelize creating multiple readers using thread local for ExcerptTailer with different names. With this approach i am overlapping the tailer indexes I didn't discover a way to paralel tailer read different indexes. This could be a nice improvement in your opinion? – Domenico Schettini Filho Jan 30 '21 at 17:33
  • @DomenicoSchettiniFilho to make the tailers parallel you need multiple threads. You can have any number of processes/threads reading a queue at once with no overhead. – Peter Lawrey Jan 30 '21 at 21:48
  • Ok. @PeterLawrey i am having bad time of reading and writing from queue. I actualy have a text field limitation. it has a ray to read and write with more performance maybe using raw or reading directly from memory. Now I am using BytesInBinaryMarshallable to write and read the object. – Domenico Schettini Filho Jan 30 '21 at 23:14
  • @DomenicoSchettiniFilho We support `List` and `String[]` what is the issue you are having. – Peter Lawrey Feb 01 '21 at 08:23
  • Hi @PeterLawrey. Actually I am using three Bytes fields and I am getting in the highest percentiles a higher number around 10 til 25 us per write to queue and read from queue. I am declaring these fields with initial size as I put in the example but even with this approach I could not improve the performance. – Domenico Schettini Filho Feb 01 '21 at 10:50
  • I think maybe fixing the maximum size could improve a little bit the performance, beacuse at the beginning i put 2048 as size of the bytes. – Domenico Schettini Filho Feb 03 '21 at 11:40
  • @DomenicoSchettiniFilho Setting the size can help a little however once it has grown to the size needed, it won't grow again. – Peter Lawrey Feb 04 '21 at 23:23