[英]Azure Service Bus Relay - Enabling Compression
使用帶有netTcpRelayBinding
和basicHttpRelayBinding
的Azure Service Bus Relay時 ,我們遇到了速度問題。 對於小消息大小( 10K ),中繼以低延遲( 100ms )運行,但隨着消息大小增加( 100K ),我們經歷看似隨機的響應時間( 600ms-1000ms )。 我們希望改善較大郵件的延遲成本。
是否正在使用通過服務總線中繼支持的消息壓縮( gzip , protobuf-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.