youbl
youbl

Reputation: 144

in IIS, System.Random.NextBytes cost high cpu usage

today, my IIS site take up hign cpu, and my server was very slowly! And I get a dump from task manager, then execute IISReset, question was solved.

In windbg, I use !runaway to find thread that long time executed, like: enter image description here

And use !clrstack to find out that top 10 thread were executing this code: System.Random.NextBytes(Byte[])), like:

Thread  30
Current frame: (MethodDesc 00007ffb5252c418 +0x20 System.Random.InternalSample())
Child-SP         RetAddr          Caller, Callee
000000487470b460 00007ffb531d8138 (MethodDesc 00007ffb5252c458 +0x28 System.Random.NextBytes(Byte[]))
000000487470b4b0 00007ffaffafe87a (MethodDesc 00007ffafeeb4e20 +0x4a Pinpoint.Core.Util.SpanIdUtil.GetNewSpanId())
000000487470b4e0 00007ffb014a53fb (MethodDesc 00007ffafeeb4e30 +0x1b Pinpoint.Core.Util.SpanIdUtil.GetNextSpanId(Int64, Int64))
000000487470b520 00007ffb014a5370 (MethodDesc 00007ffafeeb4150 +0x30 Pinpoint.Core.TraceId.GetNextTraceId())
000000487470b5a0 00007ffaffae4dab (MethodDesc 00007ffaff317ed0 +0x1cb Mike.Pinpoint.Plugin.WebRequestPlugins.TraceHttpWebRequest.BeforeGetResponse(System.Net.HttpWebRequest))
000000487470bbb0 00007ffb529444e0 (MethodDesc 00007ffb52535888 +0x80 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[]))
000000487470bcf0 00007ffb529444e0 (MethodDesc 00007ffb52535888 +0x80 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[]))
000000487470bd60 00007ffb5292f4ee (MethodDesc 00007ffb52535870 +0x8e System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo))
000000487470bde0 00007ffaffae4b79 (MethodDesc 00007ffaff318238 +0x99 Mike.Pinpoint.Plugin.WebRequestPlugins.TraceFilterImpl.BeforeGetResponseForFilter(System.Net.HttpWebRequest))
000000487470bdf0 00007ffb528f93e0 (MethodDesc 00007ffb526b1270 +0x120 System.IO.StreamWriter.Dispose(Boolean))

And here is my original code:

using System;

namespace Pinpoint.Core.Util
{
    public class SpanIdUtil
    {
        private static readonly Random rnd = new Random(Environment.TickCount);
        public const long Null = -1;

        public static long GetNewSpanId()
        {
            byte[] buf = new byte[8];
            rnd.NextBytes(buf);
            long newId = BitConverter.ToInt64(buf, 0);
            return newId;
        }

        public static long GetNextSpanId(long spanId, long parentSpanId)
        {
            long newId = GetNewSpanId();

            while (newId == spanId || newId == parentSpanId)
            {
                newId = GetNewSpanId();
            }
            return newId;
        }
    }
}

Can anybody tell me, what caused this error? Note, this only happened one time.

Upvotes: 3

Views: 111

Answers (1)

Ian Mercer
Ian Mercer

Reputation: 39277

Likely because you are sharing the same instance of Random across threads you hit a problem inside the random class as described here in which it can get stuck returning zeroes. Random is NOT thread safe.

Personally, on a server app I would NEVER use a while loop without a guard that counts down and throws an exception if it gets to zero. Unless you can prove (mathematically) that your loop will finish you should guard against it getting stuck because in a server app, when it does, you have lost a thread forever.

Upvotes: 3

Related Questions