-
Hi @alexhultman , I really want to use your library becuase its way efficient than others, but if you can help me to fix this problem of message drop, that would be very grateful of you. |
Beta Was this translation helpful? Give feedback.
Replies: 20 comments 28 replies
-
Are you saying you'd prefer it drop the connection rather than drop messages? Docs need to be updated, there is new option closeOnBackpressureLimit to drop connection rather than drop message. If you don't want it doing either you should raise limit |
Beta Was this translation helpful? Give feedback.
-
Hi, https://github.com/uNetworking/uWebSockets/releases/tag/v18.22.0 did introduce closeOnBackpressureLimit but it looks like that option was never wrapped here. |
Beta Was this translation helpful? Give feedback.
-
@rpgehlot Can you test the very latest binaries? https://github.com/uNetworking/uWebSockets.js/tree/binaries they should have closeOnBackpressureLimit option |
Beta Was this translation helpful? Give feedback.
-
Thanks for your prompt reply, but i needed centos 7 binary and i actually dont have root access so can't build that bin right now. will get it built and try out it this option. |
Beta Was this translation helpful? Give feedback.
-
Hi, I tried your new binary it seems to work, but i have a question if i increase the maxBackpressure to 11MB for e.g, how would it affect the latency of packets reaching the browsers ? would the perf suffer because of high maxbackpressure ? |
Beta Was this translation helpful? Give feedback.
-
I am seeing poor performance with maxBackpressure=11MB and closeOnBackpressureLimit : true and no drops, and low latency with maxBackpressure=6KB and closeOnBackpressureLimit:false but with message drops, i guess there is no middle ground. or is there ? |
Beta Was this translation helpful? Give feedback.
-
11MB backpressure sounds like a lot if you care about latency. If latency is a concern, set backpressure low. But either way you cannot just shove messages like there's no tomorrow - if you constantly end up with messages stuck in backpressure then you're sending too quick. |
Beta Was this translation helpful? Give feedback.
-
So, if we can't control that incoming rate, would some kind of rate limiter would be helpful which can control outward messages sent per sec to each client ? and is there a possibility we can use such a thing with publish ? |
Beta Was this translation helpful? Give feedback.
-
11MB is 2000 times larger than 6KB, the middle ground would be all the values in between
each message is 2KB? so you are publishing 800KB per second to 60 clients? or is that 2KB per sec, 5 bytes per message? |
Beta Was this translation helpful? Give feedback.
-
thats the worst case figures i have mentioned, message rate is actually variable depending on the trading volume. So yes it would amount to 800KB per sec for a single client and we have 60 such clients. most of the messages are 2KB but initial first message amounts to a little bigger value upon connection start, so thats why i used 11MB. for case when a single message is > than maxbackpressure, if i use a smaller value of 6KB then it actually closes the connection at start itself and stuck in a infinite loop since i used closeOnBackpressureLimit : true |
Beta Was this translation helpful? Give feedback.
-
I think you need to pause before sending the next message if there is backpressure on the socket if (socket.write(message) === false) {
await socket.onDrain();
} |
Beta Was this translation helpful? Give feedback.
-
So you tried 6KB which is smaller than a single message, and you tried 11MB which is 14 seconds of 800KB/sec. Have you considered trying anything between those 2 values? 800KB/sec seems like a lot, are you sure these are efficiently packed messages? Binary format etc? |
Beta Was this translation helpful? Give feedback.
-
No i haven't tried anything b/w. I encode json messages to |
Beta Was this translation helpful? Give feedback.
-
On client (Chrome), this problem is nicely solved with interface You need to do something like this for the server |
Beta Was this translation helpful? Give feedback.
-
What does this mean? does not make any sense. JSON is a utf8 string of encoded values. Sounds like you are sending JSON and trying to compress it which is inefficient way to send large amounts of data
You may want to try something between 6KB and 11MB if you are looking for middle ground |
Beta Was this translation helpful? Give feedback.
-
Can you suggest a good soln for efficiently sending large data ? |
Beta Was this translation helpful? Give feedback.
-
JSON vs binary: // data to send
data={field1:3751923517,field2:1842963572} // JSON encode
ws.send(JSON.stringify(data)) // 41 bytes of JSON utf8 string + cpu time to encode // Binary encode
buf=Buffer.allocUnsafe(8)
buf.writeUInt32BE(data.field1)
buf.writeUInt32BE(data.field2,4)
ws.send(buf,true) // 8 bytes of Binary JSON with 41 bytes is sending 5 times more than the 8 bytes of Binary and it uses more CPU to encode string. So your 800KB/sec would then be 160KB/sec. Probably would help your backpressure issue |
Beta Was this translation helpful? Give feedback.
-
I have a question regarding publish, if a websocket is subscribed to two rooms( r1, r2) and if i publish message on r1 first |
Beta Was this translation helpful? Give feedback.
-
@rpgehlot Do you have fields using less than 1 byte of data? True/false only needs 1 bit, fields with 4 values need 2 bits, 8 values need 3 bits etc, but the minimum Buffer can write is 1 byte/8 bits, to save space on those you pack the byte with multiple fields, if your data has many small value fields it saves lots of space, I use this function to pack bytes: const packBytes=(...bitsVals)=>bitsVals.reduce((byte,val,i)=>i%2?byte+val:byte<<val,0)>>>0 Tell it how many bits to use per field and the value of the field: // example data
data={field1: true, field2: false, field3: 3, field4: 15} // fields use 1 bit, 1 bit, 2 bits, 4 bits
// packBytes(bits, value[, bits, value][, bits, value]..) values are positive integers
packed=packBytes(1, data.field1, 1, data.field2, 2, data.field3, 4, data.field4) // packed.toString(2) == '10111111'
buf.writeUInt8(packed) Then you unpack it with function telling it the same bit sizes: // unpackBytes(byte, bits[, bits][, bits]..)
const unpackBytes=(byte,...bits)=>{for(let i=bits.length-1;i>=0;i--){let val=byte%(1<<bits[i]);byte>>>=bits[i];bits[i]=val}return bits}
byte=dataView.getUint8()
[field1,field2,field3,field4]=unpackBytes(byte, 1, 1, 2, 4) // field1 == true; field2 == false; field3 == 3; field4 == 15 You can also use the same functions to pack data into 16 or 32 bit spaces if more room is needed, this allows you to be most efficient without wasting any bits. Maybe you have an array of items that need 32 bits each, then you pack it with exactly how many bits each field needs Compare byte size with other encodings:// encode data
const data={field1:true,field2:false,field3:3,field4:15}
const msgpack=require('@msgpack/msgpack')
const avscSchema=require('avsc').Type.forValue(data)
const packBytes=(...bitsVals)=>bitsVals.reduce((byte,val,i)=>i%2?byte+val:byte<<val,0)>>>0
const encodeFns={
packBytes:data=>{
const buf=Buffer.allocUnsafe(1)
buf.writeUInt8(packBytes(1,data.field1,1,data.field2,2,data.field3,4,data.field4))
return buf
},
avsc:data=>avscSchema.toBuffer(data),
msgpack:data=>msgpack.encode(data),
json:data=>Buffer.from(JSON.stringify(data)),
}
// node benchmark.js [encodings=all] [iterations=2_000_000]
const encodings=process.argv[2]&&process.argv[2]!='all'?[process.argv[2]]:Object.keys(encodeFns)
const iterations=process.argv[3]||2_000_000
encodings.forEach(type=>{
let i=iterations,time=process.hrtime.bigint()
while(i--)encodeFns[type](data)
console.log(`${type} encode time(ns): ${Math.floor(Number(process.hrtime.bigint()-time)/iterations)} - bytes: ${encodeFns[type](data).length}`)
})
|
Beta Was this translation helpful? Give feedback.
-
Hello, is it possible under any scenario for uws to drop any message for any client even if i have closeOnBackPressureLimit set to true ? |
Beta Was this translation helpful? Give feedback.
@rpgehlot Do you have fields using less than 1 byte of data? True/false only needs 1 bit, fields with 4 values need 2 bits, 8 values need 3 bits etc, but the minimum Buffer can write is 1 byte/8 bits, to save space on those you pack the byte with multiple fields, if your data has many small value fields it saves lots of space, I use this function to pack bytes:
Tell it how many bits to use per field and the value of the field: