コード例 #1
0
        private static void Run_Limit_Test(int?intervalLimit, int numberPerBurst, int numberOfBursts, int millisecondsBetweenBursts)
        {
            var actualIntervalLimit = intervalLimit ?? DefaultLimitPerSecond;

            var test = new RateLimitLoadTest()
            {
                NumberPerBurst    = numberPerBurst,
                TimeBetweenBursts = TimeSpan.FromMilliseconds(millisecondsBetweenBursts),
                NumberOfBursts    = numberOfBursts
            };

            var result = RunTest(intervalLimit, test);

            var totalMilliseconds = result.TimeElapsed.TotalMilliseconds;

            var expectedLimit = totalMilliseconds * actualIntervalLimit / 1_000;

            var acceptableUpperVariance = (actualIntervalLimit * 1.0);
            var acceptableLowerVariance = (actualIntervalLimit * 1.15); // Allow for increased tolerance on lower limit since the rolling window does not get dequeued as quickly as it can queued
            var upperLimit = expectedLimit + acceptableUpperVariance;
            var lowerLimit = expectedLimit - acceptableLowerVariance;

            Assert.True(
                result.TotalAllowed >= lowerLimit && result.TotalAllowed <= upperLimit,
                $"Expected between {lowerLimit} and {upperLimit}, received {result.TotalAllowed} out of {result.TotalAttempted} within {totalMilliseconds} milliseconds.");

            // Rate should match for the last two intervals, which is a total of two seconds
            var numberOfBurstsWithinTwoIntervals = 2_000 / millisecondsBetweenBursts;
            var totalExpectedSent    = numberOfBurstsWithinTwoIntervals * numberPerBurst;
            var totalExpectedAllowed = 2 * actualIntervalLimit;
            var expectedRate         = totalExpectedAllowed / (float)totalExpectedSent;

            var lowestRate = expectedRate - 0.40f;

            if (lowestRate < 0)
            {
                lowestRate = expectedRate / 2;
            }

            var highestRate = expectedRate + 0.40f;

            Assert.True(
                result.ReportedRate >= lowestRate && result.ReportedRate <= highestRate,
                $"Expected rate between {lowestRate} and {highestRate}, received {result.ReportedRate}.");
        }
コード例 #2
0
        private static void Run_Limit_Test(int?intervalLimit, int numberPerBurst, int numberOfBursts, int millisecondsBetweenBursts)
        {
            var actualIntervalLimit = intervalLimit ?? DefaultLimitPerSecond;

            var test = new RateLimitLoadTest()
            {
                NumberPerBurst    = numberPerBurst,
                TimeBetweenBursts = TimeSpan.FromMilliseconds(millisecondsBetweenBursts),
                NumberOfBursts    = numberOfBursts
            };

            var result = RunTest(intervalLimit, test);

            var totalMilliseconds = result.TimeElapsed.TotalMilliseconds;

            var expectedLimit        = totalMilliseconds * actualIntervalLimit / 1_000;
            var acceptableDifference = (actualIntervalLimit * 0.80);
            var upperLimit           = expectedLimit + acceptableDifference;
            var lowerLimit           = expectedLimit - acceptableDifference;

            Assert.True(
                result.TotalAllowed >= lowerLimit && result.TotalAllowed <= upperLimit,
                $"Expected between {lowerLimit} and {upperLimit}, received {result.TotalAllowed} out of {result.TotalAttempted} within {totalMilliseconds} milliseconds.");

            // Rate should match for the last two intervals, which is a total of two seconds
            var numberOfBurstsWithinTwoIntervals = 2_000 / millisecondsBetweenBursts;
            var totalExpectedSent    = numberOfBurstsWithinTwoIntervals * numberPerBurst;
            var totalExpectedAllowed = 2 * actualIntervalLimit;
            var expectedRate         = totalExpectedAllowed / (float)totalExpectedSent;

            var maxPercentVariance = 0.35f;
            var lowestRate         = expectedRate - maxPercentVariance;
            var highestRate        = expectedRate + maxPercentVariance;

            Assert.True(
                result.ReportedRate >= lowestRate && result.ReportedRate <= highestRate,
                $"Expected rate between {lowestRate} and {highestRate}, received {result.ReportedRate}.");
        }
コード例 #3
0
        private static RateLimitResult RunTest(int?intervalLimit, RateLimitLoadTest test)
        {
            var parallelism = test.NumberPerBurst;

            if (parallelism > Environment.ProcessorCount)
            {
                parallelism = Environment.ProcessorCount;
            }

            var clock = new SimpleClock();

            var limiter         = new RateLimiter(maxTracesPerInterval: intervalLimit);
            var barrier         = new Barrier(parallelism + 1, _ => clock.UtcNow += test.TimeBetweenBursts);
            var numberPerThread = test.NumberPerBurst / parallelism;
            var workers         = new Task[parallelism];
            int totalAttempted  = 0;
            int totalAllowed    = 0;

            for (int i = 0; i < workers.Length; i++)
            {
                workers[i] = Task.Factory.StartNew(
                    () =>
                {
                    using var lease = Clock.SetForCurrentThread(clock);

                    for (var i = 0; i < test.NumberOfBursts; i++)
                    {
                        // Wait for every worker to be ready for next burst
                        barrier.SignalAndWait();

                        for (int j = 0; j < numberPerThread; j++)
                        {
                            // trace id and span id are not used in rate-limiting
                            var spanContext = new SpanContext(TraceId.CreateFromInt(1), spanId: 1, serviceName: "Weeeee");

                            // pass a specific start time since there is no TraceContext
                            var span = new Span(spanContext, DateTimeOffset.UtcNow);

                            Interlocked.Increment(ref totalAttempted);

                            if (limiter.Allowed(span))
                            {
                                Interlocked.Increment(ref totalAllowed);
                            }
                        }
                    }
                },
                    TaskCreationOptions.LongRunning);
            }

            // Wait for all workers to be ready
            barrier.SignalAndWait();

            // We do not need to synchronize with workers anymore
            barrier.RemoveParticipant();

            // Wait for workers to finish
            Task.WaitAll(workers);

            var result = new RateLimitResult
            {
                RateLimiter    = limiter,
                ReportedRate   = limiter.GetEffectiveRate(),
                TotalAttempted = totalAttempted,
                TotalAllowed   = totalAllowed
            };

            return(result);
        }
コード例 #4
0
        private static RateLimitResult RunTest(int?intervalLimit, RateLimitLoadTest test)
        {
            var parallelism = test.NumberPerBurst;

            if (parallelism > 10)
            {
                parallelism = 10;
            }

            var resetEvent = new ManualResetEventSlim(initialState: false); // Start blocked

            var workerReps = Enumerable.Range(1, parallelism).ToArray();

            var registry = new ConcurrentQueue <Thread>();

            var result = new RateLimitResult();

            var start   = DateTime.Now;
            var limiter = new RateLimiter(maxTracesPerInterval: intervalLimit);
            var end     = DateTime.Now;
            var endLock = new object();

            var traceContext = new TraceContext(Tracer.Instance);

            for (var i = 0; i < test.NumberOfBursts; i++)
            {
                var remaining = test.NumberPerBurst;

                var workers =
                    workerReps
                    .Select(t => new Thread(
                                thread =>
                {
                    resetEvent.Wait();
                    while (remaining > 0)
                    {
                        Interlocked.Decrement(ref remaining);

                        var spanContext = new SpanContext(null, traceContext, "Weeeee");
                        var span        = new Span(spanContext, null);

                        if (limiter.Allowed(span))
                        {
                            result.Allowed.Add(span.SpanId);
                        }
                        else
                        {
                            result.Denied.Add(span.SpanId);
                        }
                    }

                    lock (endLock)
                    {
                        end = DateTime.Now;
                    }
                }));

                foreach (var worker in workers)
                {
                    registry.Enqueue(worker);
                    worker.Start();
                }

                resetEvent.Set();

                Thread.Sleep(test.TimeBetweenBursts);

                resetEvent.Reset();
            }

            while (!registry.IsEmpty)
            {
                if (registry.TryDequeue(out var item))
                {
                    if (item.IsAlive)
                    {
                        registry.Enqueue(item);
                    }
                }
            }

            result.RateLimiter  = limiter;
            result.ReportedRate = limiter.GetEffectiveRate();
            result.TimeElapsed  = end.Subtract(start);

            return(result);
        }
コード例 #5
0
        private static RateLimitResult RunTest(int?intervalLimit, RateLimitLoadTest test)
        {
            var parallelism = test.NumberPerBurst;

            if (parallelism > 10)
            {
                parallelism = 10;
            }

            var result = new RateLimitResult();

            var limiter = new RateLimiter(maxTracesPerInterval: intervalLimit);

            var traceContext = new TraceContext(Tracer.Instance);

            var barrier = new Barrier(parallelism + 1);

            var numberPerThread = test.NumberPerBurst / parallelism;

            var workers = new Task[parallelism];

            for (int i = 0; i < workers.Length; i++)
            {
                workers[i] = Task.Factory.StartNew(
                    () =>
                {
                    var stopwatch = new Stopwatch();

                    for (var i = 0; i < test.NumberOfBursts; i++)
                    {
                        // Wait for every worker to be ready for next burst
                        barrier.SignalAndWait();

                        stopwatch.Restart();

                        for (int j = 0; j < numberPerThread; j++)
                        {
                            var spanContext = new SpanContext(null, traceContext, "Weeeee");
                            var span        = new Span(spanContext, null);

                            if (limiter.Allowed(span))
                            {
                                result.Allowed.Add(span.SpanId);
                            }
                            else
                            {
                                result.Denied.Add(span.SpanId);
                            }
                        }

                        var remainingTime = (test.TimeBetweenBursts - stopwatch.Elapsed).TotalMilliseconds;

                        if (remainingTime > 0)
                        {
                            Thread.Sleep((int)remainingTime);
                        }
                    }
                },
                    TaskCreationOptions.LongRunning);
            }

            // Wait for all workers to be ready
            barrier.SignalAndWait();

            var sw = Stopwatch.StartNew();

            // We do not need to synchronize with workers anymore
            barrier.RemoveParticipant();

            // Wait for workers to finish
            Task.WaitAll(workers);

            result.TimeElapsed  = sw.Elapsed;
            result.RateLimiter  = limiter;
            result.ReportedRate = limiter.GetEffectiveRate();

            return(result);
        }
コード例 #6
0
        private static RateLimitResult RunTest(int?intervalLimit, RateLimitLoadTest test)
        {
            var parallelism = test.NumberPerBurst;

            if (parallelism > 10)
            {
                parallelism = 10;
            }

            var limiter         = new RateLimiter(maxTracesPerInterval: intervalLimit);
            var barrier         = new Barrier(parallelism + 1);
            var numberPerThread = test.NumberPerBurst / parallelism;
            var workers         = new Task[parallelism];
            int totalAttempted  = 0;
            int totalAllowed    = 0;

            for (int i = 0; i < workers.Length; i++)
            {
                workers[i] = Task.Factory.StartNew(
                    () =>
                {
                    var stopwatch = new Stopwatch();

                    for (var i = 0; i < test.NumberOfBursts; i++)
                    {
                        // Wait for every worker to be ready for next burst
                        barrier.SignalAndWait();

                        stopwatch.Restart();

                        for (int j = 0; j < numberPerThread; j++)
                        {
                            // trace id and span id are not used in rate-limiting
                            var spanContext = new SpanContext(traceId: 1, spanId: 1, serviceName: "Weeeee");

                            // pass a specific start time since there is no TraceContext
                            var span = new Span(spanContext, DateTimeOffset.UtcNow);

                            Interlocked.Increment(ref totalAttempted);

                            if (limiter.Allowed(span))
                            {
                                Interlocked.Increment(ref totalAllowed);
                            }
                        }

                        var remainingTime = (test.TimeBetweenBursts - stopwatch.Elapsed).TotalMilliseconds;

                        if (remainingTime > 0)
                        {
                            Thread.Sleep((int)remainingTime);
                        }
                    }
                },
                    TaskCreationOptions.LongRunning);
            }

            // Wait for all workers to be ready
            barrier.SignalAndWait();

            var sw = Stopwatch.StartNew();

            // We do not need to synchronize with workers anymore
            barrier.RemoveParticipant();

            // Wait for workers to finish
            Task.WaitAll(workers);

            var result = new RateLimitResult
            {
                TimeElapsed    = sw.Elapsed,
                RateLimiter    = limiter,
                ReportedRate   = limiter.GetEffectiveRate(),
                TotalAttempted = totalAttempted,
                TotalAllowed   = totalAllowed
            };

            return(result);
        }