簡體   English   中英

Azure Service Bus Relay - 啟用壓縮

[英]Azure Service Bus Relay - Enabling Compression

使用帶有netTcpRelayBindingbasicHttpRelayBindingAzure Service Bus Relay時 ,我們遇到了速度問題。 對於小消息大小( 10K ),中繼以低延遲( 100ms )運行,但隨着消息大小增加( 100K ),我們經歷看似隨機的響應時間( 600ms-1000ms )。 我們希望改善較大郵件的延遲成本。

是否正在使用通過服務總線中繼支持的消息壓縮( gzipprotobuf-net )? 有沒有人通過中繼啟用請求/響應壓縮成功? 通過IIS支持響應壓縮微不足道的 ,但我們希望支持請求壓縮以提高延遲成本。 由於我們無法用Fiddler來描述中繼,我們如何知道消息在通過中繼時仍然被壓縮?


我們發現一個有趣的觀點是,在后續消息中繼( 2s )之間引入延遲,我們可以獲得更好的性能( 100K - 200ms )。 可能是更大的消息被自動限制? 知道觸發限制條件的消息大小截止值會很高興。

對於我們的測試 - 我們只是向服務中繼發送一個隨機消息字符串,並從服務器回送請求字符串。 我們嘗試了來自多個地理位置的此客戶端/服務器( 以排除防火牆/ Web過濾器問題 )並遇到相同的延遲行為。

服務器端

public class ServiceRelayProfiler : IServiceRelayProfiler
{
    public string HelloProfiler(string name)
    {
        return string.Format("Hello {0}", name);
    }
}

客戶端

ChannelFactory<IServiceRelayProfiler> channelFactory = new ChannelFactory<IServiceRelayProfiler>("helloProfilerTcp");
IServiceRelayProfiler channel = channelFactory.CreateChannel();
string message = RandomString(100000); // 100K
for (int i = 0; i < 100; i++)
{
    DateTime start = DateTime.Now;
    string response = channel.HelloProfiler(message);
    DateTime end = DateTime.Now;
    TimeSpan duration = end - start;
    Console.WriteLine("Response is: {0} at {1}\tDuration: {2}ms", response.Substring(0, 20) + "....", end, duration.Milliseconds);
    //Thread.Sleep(2000); // delay makes response times more consistent
}

這不是一個完整的答案,但在服務器端,您可以將其添加到global.asax.cs以允許請求解壓縮:

public class MvcApplication : System.Web.HttpApplication
{    
    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        //Activate request decompression
        string contentEncoding = Request.Headers["Content-Encoding"];
        if (contentEncoding != null && contentEncoding.Equals("gzip", StringComparison.CurrentCultureIgnoreCase))
        {
            Request.Filter = new GZipStream(Request.Filter, CompressionMode.Decompress, true);
        }
    }
}

您可以嘗試的一件事是通過System.IO.Compression壓縮消息(請參閱下面的util - 您可以添加為擴展名)。

但是在排隊/節流問題上。 較大的消息總是比較小/優化的塊更多地滯后於網絡。 如果你可以將數據分解到50k或更低或者使用udp,它可以通過比tcp更少的排隊和驗證來傳輸。

TCP數據包大小的絕對限制是64K(65535字節),但實際上這遠遠大於您將看到的任何數據包的大小,因為較低層(例如以太網)具有較低的數據包大小。

例如,以太網的MTU(最大傳輸單元)為1500字節。 某些類型的網絡(如令牌環)具有更大的MTU,並且某些類型具有更小的MTU,但是每個物理技術的值是固定的。

從此處: TCP連接的最大數據包大小

當你分手時,事情會變得更順暢,多人游戲對此有所幫助,他們還使用udp來限制額外的驗證(實現可靠的udp來驗證單個消息並僅在需要時進行排序)。

CompressionUtil類,在發送/接收之前壓縮消息輸入和輸出: https//gist.github.com/drawcode/8948293

public static class CompressUtil {

    public static string ToCompressed(this string val) {
        if (!IsStringCompressed(val)) {
            return CompressString(val);
        }
        return val;
    }

    public static string ToDecompressed(this string val) {
        if (IsStringCompressed(val)) {
            return DecompressString(val);
        }
        return val;
    }

    public static string CompressString(string text) {
        byte[] buffer = Encoding.UTF8.GetBytes(text);
        var memoryStream = new MemoryStream();
        using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) {
            gZipStream.Write(buffer, 0, buffer.Length);
        }

        memoryStream.Position = 0;

        var compressedData = new byte[memoryStream.Length];
        memoryStream.Read(compressedData, 0, compressedData.Length);

        var gZipBuffer = new byte[compressedData.Length + 4];
        Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
        Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
        return Convert.ToBase64String(gZipBuffer);
    }

    public static string DecompressString(string compressedText) {
        byte[] gZipBuffer = Convert.FromBase64String(compressedText);
        using (var memoryStream = new MemoryStream()) {
            int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
            memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4);

            var buffer = new byte[dataLength];

            memoryStream.Position = 0;
            using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) {
                gZipStream.Read(buffer, 0, buffer.Length);
            }

            return Encoding.UTF8.GetString(buffer);
        }
    }

    public static bool IsStringCompressed(string data) {
        if (IsStringCompressedGZip(data) || IsStringCompressedPKZip(data)) {
            return true;
        }
        return false;
    }

    public static bool IsStringCompressedGZip(string data) {
        return CheckSignatureString(data, 3, "1F-8B-08");
    }

    public static bool IsStringCompressedPKZip(string data) {
        return CheckSignatureString(data, 4, "50-4B-03-04");
    }

    public static bool CheckSignatureFile(string filepath, int signatureSize, string expectedSignature) {
        if (String.IsNullOrEmpty(filepath))
            throw new ArgumentException("Must specify a filepath");
        if (String.IsNullOrEmpty(expectedSignature))
            throw new ArgumentException("Must specify a value for the expected file signature");
        using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
            if (fs.Length < signatureSize)
                return false;
            byte[] signature = new byte[signatureSize];
            int bytesRequired = signatureSize;
            int index = 0;
            while (bytesRequired > 0) {
                int bytesRead = fs.Read(signature, index, bytesRequired);
                bytesRequired -= bytesRead;
                index += bytesRead;
            }
            string actualSignature = BitConverter.ToString(signature);
            if (actualSignature == expectedSignature)
                return true;
            else
                return false;
        }
    }

    public static bool CheckSignatureString(string data, int signatureSize, string expectedSignature) {

        byte[] datas = Encoding.ASCII.GetBytes(data);
        using (MemoryStream ms = new MemoryStream(datas)) {
            if (ms.Length < signatureSize)
                return false;
            byte[] signature = new byte[signatureSize];
            int bytesRequired = signatureSize;
            int index = 0;
            while (bytesRequired > 0) {
                int bytesRead = ms.Read(signature, index, bytesRequired);
                bytesRequired -= bytesRead;
                index += bytesRead;
            }
            string actualSignature = BitConverter.ToString(signature);
            if (actualSignature == expectedSignature)
                return true;
            else
                return false;
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM