Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request Problem #73

Closed
s921102002 opened this issue May 26, 2016 · 9 comments
Closed

Request Problem #73

s921102002 opened this issue May 26, 2016 · 9 comments

Comments

@s921102002
Copy link

Hi, I play the example Requestor and Replier.
I found there's a exception when request return because
In Conn.cs

        internal virtual Msg request(string subject, byte[] data, int timeout)
        {
            Msg    m     = null;
            string inbox = NewInbox();

            SyncSubscription s = subscribeSync(inbox, null);
            s.AutoUnsubscribe(1);

            publish(subject, inbox, data);
            m = s.NextMessage(timeout);
            try
            {
                // the auto unsubscribe should handle this.
                s.Unsubscribe();
            }
            catch (Exception) {  /* NOOP */ }

            return m;
        }

when s.NextMessage(timeout);

            if (msg != null)
            {
                long d = tallyDeliveredMessage(msg);
                if (d == max)
                {
                    // Remove subscription if we have reached max.
                    localConn.removeSub(this);
                }
                if (localMax > 0 && d > localMax)
                {
                    throw new NATSMaxMessagesException();
                }
            }

localConn.removeSub(this);

so

       internal virtual void removeSub(Subscription s)
        {
            Subscription o;

            subs.TryRemove(s.sid, out o);
            if (s.mch != null)
            {
                s.mch.close();
                s.mch = null;
            }

            s.conn = null;
            s.closed = true;
        }

s.conn = null; here, but next return to Conn.cs and execute

              // the auto unsubscribe should handle this.
                s.Unsubscribe();
        public virtual void Unsubscribe()
        {
            Connection c;
            lock (mu)
            {
                c = this.conn;
            }

            if (c == null)
                throw new NATSBadSubscriptionException();

            c.unsubscribe(this, 0);
        }

the exception here

 if (c == null)
    throw new NATSBadSubscriptionException();

I have two problems

  1. when execute request and the max count =1 and unsubscribe in NextMessage() function so c always null here and the exception always throw?

2.if throw new NATSBadSubscriptionException(); it has significant impact on performance, and Is this a bug? or can I delete this exception such as if (c == null) return; ???

or is there something wrong with me?

Thanks All

@ColinSullivan1
Copy link
Member

Hello @s921102002, thank you for your interest in NATS! Good observations!

  1. That is present to parallel the go client - the Unsubscription is there to cover the case the server did not process the message or a failover happened down during the request. In most cases it should have no effect.
  2. There is a performance impact. I'm not sure how significant it is with respect to the entire request reply call, but good catch there!

I've updated to account for these with #75. Does this address your questions/issues?

@s921102002
Copy link
Author

Hi, ColinSullivan1 #75 is not my issues, and I download the lastest csnats-0.5.0 this question solved, but I test Result

Replied to 20000 msgs in 20.090046 seconds (995 replies/second).
Statistics:
   Incoming Payload Bytes: 80000
   Incoming Messages: 20000
   Outgoing Payload Bytes: 100000
   Outgoing Messages: 20000

and I think it's too slow?
but it maybe not csnats problem, or is my environment problem( because this computer is not very clean such as it installed anti-virus).
Can anyone run the example Requestor and Replier and post result here.
and I can compare 995 replies/second is normal or abnormal?
if it's abnormal I want to find the problem.
I test on win7 32bit and cpu is i7-5930k
Thanks all :)

@ColinSullivan1
Copy link
Member

ColinSullivan1 commented May 27, 2016

@s921102002, That does seem very low. I just tested on a win7 VM, and am getting around 3000 replies/sec, and I consider that low. I'll look at some performance profiling of the request API. What are your publish and subscribe rates?

@s921102002
Copy link
Author

Hi @ColinSullivan1, below is my pub/sub result (send 100 bytes) test on same machine

Receiving 1000000 messages on subject foo
  Url: nats://localhost:4222
  Receiving: Asynchronously
Received 1000228 msgs in 1.2408213 seconds (806101 msgs/second).
Statistics:
   Incoming Payload Bytes: 100096700
   Incoming Messages: 1000967

I think it's ok and nearly the same as golang client.
but why req/rep so slow? I think there's some problems in req/rep
Thanks

@s921102002
Copy link
Author

Hi @ColinSullivan1, I found if comment this line in Conn.cs

 // Yield for a millisecond.  This reduces resource contention,
 // increasing throughput by about 50%.
---->  //Thread.Sleep(1);

the performance will speed up, but still slow.
I think this problem maybe relate to flush

In fact I don't know why nats need flush function.
if you change the Publish example code to

 for (int i = 0; i < count; i++)
 {
     c.Publish(subject, payload);
-->  c.Flush();
 }

->not here

the performance will be very very slow.
so is nats high performance?

If I don't have call c.Flush(),

  1. when does it send data to subscriber? Does OS decide it?
    2.is there some data never be send?
    3.what does the mechanism(send and receive) about NATS client?

consider below situation

If I want to do real-time publish( it need microseconds even nanoseconds latency) so is NATS suitable? and when I should call flush function if I need fastest send data to subscriber? and can I disable nagle algorithm on socket if I need a high resolution time?

there's a little conflict, if i call flush function, the performance will be slow, but if i don't have call flush,
it's not very real-time? so should I call flush in real-time case?

Sorry, I just begin to NATS for some days, so if i have something misunderstand, please bear with me.

Thanks :)

@ColinSullivan1
Copy link
Member

Based on your pub/sub numbers, I think your results are congruent with mine, so this is something we can certainly improve upon in NATS.

The Request API does quite a bit internally, which involves communication with the server:

  • It creates a subscription on a new inbox,
  • Auto unsubscribes
  • Publishes the message
  • Flushes the message - Note: this is costly for throughput, but reduces latency.
  • Receives the new message
  • Unsubscribes to handle corner cases.

Thank you for pointing this out - There's room to improve performance here.

@ColinSullivan1
Copy link
Member

There is always a trade off between latency and throughput. NATS by default favors throughput, however the IConnection.Flush() API can be used reduce latency. The NATS client has a thread that occasionally flushes buffered data, similar to the Nagle algorithm, but optimized for throughput. It sounds as if you need lower latency - in which case you'll want to call Flush() after Publish(...), to ensure your message is immediately sent to the server.

@s921102002
Copy link
Author

Hi, @ColinSullivan1 Thank you for your reply :)
So should I close this issue?

@ColinSullivan1
Copy link
Member

ColinSullivan1 commented May 28, 2016

I'm glad I could help, and thank you for identifying an area that we can improve upon. Much appreciated! #78 should address this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants