"max allowed size 128000 bytes" reached when there are a lot of publisher/subscribers - akka.net

Im using distributed pub/sub in an Akka.net cluster and I've begun seeing this error when pub/sub grows to approx. 1000 subscribers and 3000 publishers.
max allowed size 128000 bytes, actual size of encoded Akka.Cluster.Tools.PublishSubscribe.Internal.Delta was 325691 bytes
I don't know, but I'm guessing distributed pub/sub is trying to pass the pub/sub list to other actor systems on the cluster?
Anyway, I'm a little hesitant about boosting size limits because of this post. So what would be a reasonable approach to correcting this?

You may want to tackle with distributed pub/sub HOCON settings. Messages in Akka.Cluster.DistributePubSub are grouped together and send as deltas. You may be interested in two settings:
akka.cluster.pub-sub.max-delta-elements = 3000 says how many items can maximally consist on delta message. 3000 is the default value and you may want to lower it in order to reduce the size of the delta message (which seems to be an issue in your case).
akka.cluster.pub-sub.gossip-interval = 1s indirectly affects how often gossips will be sent. The more often they're send, the smaller they may be - assuming continuously highly saturated channel.
If these won't help, you may also think about reducing the size of your custom messages by introducing custom serializers with smaller payload footprint.

Related

Thousands of REDIS Sorted Sets VS millions of Simple Sets

I came to 2 options on how to solve the problem I have with (AWS ElastiCache (REDIS)).
I was able to find all the differences for these two approaches in scope of Time complexity (Big O) and other stuff.
However, there is one question that still bothers me:
Is there any difference for REDIS cluster (in memory consumption, CPU or any other resources) to handle:
500K larger Sorted Sets (https://redis.io/commands#sorted_set) containing ~100K elements each
48MLN smaller Simple Sets (https://redis.io/commands#set) containing ~500 elements each
?
Thanks in advance for the help :)
You are comparing two different data types, it is better to be benchmarked to decide which one's memory consumption is better with info memory. But I assume both are used with the same length for entries inside.
If you use the config set-max-intset-entries and stay in the limits of it while adding to this set(let's say 512), then your memory consumption will be lower than your first option(same value lengths and equality of the total entries). But it doesn't come for free.
The documentation states that
This is completely transparent from the point of view of the user and API. Since this is a CPU / memory trade off it is possible to tune the maximum number of elements and maximum element size for special encoded types using the following redis.conf directives.

Optimizing Redis cluster nodes

I understand that in a Redis cluster, there are 16384 slots total distributed across the nodes. So if I have a key like this entity:user:userID (like user:1234) and the value is a serialized user object and say if my application has 500k+ users. It should get distributed to each slots evenly. We currently have 6 nodes total (3 masters and 3 slaves), and we are always wondering when we shall add 2 more nodes to 8 total. We also do write the cache data to disk, and sometimes we do get latency warning when persisting to disk. I'd assume if there are more nodes, there are less data to persist for each node, thus a better performance/usage of resources. But asides from disk i/o, is there a dead-on performance measurement to let us know when we should start adding additional nodes?
Thanks!
If your limiting factor is disk I/O for replication, using SSDs can drastically improve performance.
Two additional signs that it is time to scale out include server load and used memory for your nodes. There are others, but these two are simple to reason about.
If your limiting factor is processing power on the nodes (e.g. server load) because of a natural increase in requests, scaling out will help distribute the load across more nodes. If one node is consistently higher than the others, this could indicate a hot partition, which is a separate problem to solve.
If your limiting factor is total storage capacity (e.g. used memory) because of a natural increase in data stored in your cache, scaling out will help grow the total storage capacity of your cluster. If you have a very large dataset and the set of keys used on a regular basis is small, technologies such as Redis on Flash by Redis Labs may be applicable.

Why redis cluster only have 16384 slots?

In my opinion, with the development of keys, the 'hash conflict' will occurs more and more frequently. I have no idea if those keys on the same slot are stored in singly linked list, then read performance will be effected, especially the stale record?
answer from antirez, the author of Redis, below.
The reason is:
Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.
At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.
So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.
These "slots" are merely a unit of distribution across shards. You're not going to have of 16K shards servers in a cluster; but the are granular enough to allow some degree of weighted load distribution. (For example if you start with four shard on one type of hardware and choose to introduce two more of a more power profile, you could make the new servers targets for twice as many slots as the existing servers and thus achieve a more even relatively utilization of your capacity.
I'm just summarizing the gist of how they're used. For details read the Redis Cluster Specification.

boto dynamodb: is there a way to optimize batch writing?

I am indexing large amounts of data into DynamoDB and experimenting with batch writing to increase actual throughput (i.e. make indexing faster). Here's a block of code (this is the original source):
def do_batch_write(items,conn,table):
batch_list = conn.new_batch_write_list()
batch_list.add_batch(table, puts=items)
while True:
response = conn.batch_write_item(batch_list)
unprocessed = response.get('UnprocessedItems', None)
if not unprocessed:
break
# identify unprocessed items and retry batch writing
I am using boto version 2.8.0. I get an exception if items has more than 25 elements. Is there a way to increase this limit? Also, I noticed that sometimes, even if items is shorter, it cannot process all of them in a single try. But there does not seem to be correlation between how often this happens, or how many elements are left unprocessed after a try, and the original length of items. Is there a way to avoid this and write everything in one try? Now, the ultimate goal is to make processing faster, not just avoid repeats, so sleeping for a long period of time between successive tries is not an option.
Thx
From the documentation:
"The BatchWriteItem operation puts or deletes multiple items in one or more tables. A single call to BatchWriteItem can write up to 16 MB of data, which can comprise as many as 25 put or delete requests. Individual items to be written can be as large as 400 KB."
The reason for some not succeeded is probably due to exceeding the provisioned throughput of your table. Do you have other write operations being performed on the table at the same time? Have you tried increasing the write throughput on your table to see if more items are processed.
I'm not aware of any way of increasing the limit of 25 items per request but you could try asking on the AWS Forums or through your support channel.
I think the best way to get maximum throughput is to increase the write capacity units as high as you can and to parallelize the batch write operations across several threads or processes.
From my experience, there is little to be gained in trying to optimize your write throughput using either batch write or multithreading. Batch write saves a little network time, and multithreading saves close to nothing as the item size limitation is quite low and the bottleneck is very often DDB throttling your request.
So (like it or not) increasing your Write Capacity in DynamoDB is the way to go.
Ah, like garnaat said, latency inside the region is often really different (like from 15ms to 250ms) from inter-region or outside AWS.
Not only increasing the Write Capacity will make it faster.
if your HASH KEY diversity is poor, then even if you will increase your write capacity, then you can have throughput errors.
throughput errors are depends on your hit map.
example: if your hash key is a number between 1-10, and you have 10 records with hash value 1-10 but 10k records with value 10, then you will have many throughput errors even while increasing your write capacity.

WCF: Choosing between increasing maximum array length and splitting the message into smaller packages

Side note: even if the question was posted several months ago, I'm still in search of a good answer so any feedback is welcomed.
While developing WCF Web Services I have encountered the error:
The maximum array length quota (16384) has been exceeded while reading XML data.
like many others and have solved it by modifying the binding configuration.
When looking for answers on the Internet, the solution was almost always changing the binding configuration, setting the maxArrayLength to maximum, going to Streamed transfer.
In some situations, like in this question WCF sending huge data , people suggest modifying the binding configuration over transmiting data in smaller chunks.
But the maximum values and streamed transfer will always work? Even in a system where you may never know what maximum size will have the data?
How to choose between the two options?
It depends on what you transfer? Downloading media vs. returning large log information?
The answer given to me until now revolves around technical aspects of streaming, but the answer I am looking for should be more focused on guidelines in the situation exposed, about choosing between the two options.
Not all bindings support streaming. The only ones that do are basicHttpBinding, NetTcpBinding, NetNamedPipeBinding, and WebHttpBinding. You also do not get to do reliable sessions if using streaming.
So why the big deal about streaming for large messages? Well if you don't use streaming, it is going to load the entire message in the memory buffer which can kill the available resources.
For more information, see this on MSDN: MSDN Large Message Transfers