On sharing your opinion

Two short stories, one topic.

1

Imagine the following scenario. An interesting discussion that gets people excited. There’s this one new person that doesn’t get involved too much. Actually, if you were counting all the words they said, the number would be 0. Nothing, none, null. The reason for this is simple. They did not go through the same as the rest. The experience in this topic, if any, is none. Their reasoning as simple as that: no exp, no talk. Is it a valid approach?

2

Imagine the following scenario. An interesting discussion that gets people excited. There’s this one person that gets involved. They share all the experiences they had with the topic. The reasoning they share, the experience, is so big, that all the rest just follows their words. The speaker’s reasoning as simple as that: big exp, big talk. Is it a valid approach?

What to do?

Recently, I came to a conclusion that there’s no simple answer to these questions. Being an expert, sometimes requires you to be quiet for a little. To listen to others’ experiences and to not flood them with your opinions. They may just follow you.
Being a novice, sometimes requires you to share, what you don’t know. Just to show a new point of view.
 
Next time, when debating, think about your opinions again. Maybe, it’s time to make it the other way around.

Never ending Append Blobs

In this article I’ll describe an easy and fast way to use Azure Storage Append Blobs to create a never ending Append Blob. Yes, a regular Append Blob has its limitations, including the maximum number of blocks and the size, but with a proper design we can overcome them.

Limits we want to overcome

According to Azure Subscription Storage Limits, an Append Blob is limited in the following way:

  1. Max number of blocks in an append blob: 50,000 – this means that we can append to a single blob only 50,000 times, no matter how much data we add at the same time
  2. Max size of a block in an append blob: 4 MiB – this means that a single operation adding one chunk of data, cannot contain more than 4 MiB.

If we could address the first, it’s highly unlikely that we’d need to address the second. 4 MiB is just enough for a single append operation.

Overcoming the limited number of blocks

Let’s consider a single writer case. Now, agree that we’ll use natural number (1, 2, 3, …) to name blobs. Then, whenever an append operation is about to happen, the writer could check the number of already appended blocks by fetching blob’s properties and create another one, if the number is equal to the max number of blocks. We could also try to append and catch the StorageException, checking for BlockCountExceedsLimit error code (see Blob Error Codes for more). Then, we’d follow with creating another blob and appending to the newly created one. This case is easy. What about multiple processes, writers trying to append at the same time?

Multiple writers

Multiple writers could use a similar approach. There’s also a risk of not being able to check for the limit. When you fetch attributes, another writer could already append their block making the number invalid. We could stick with the exception handling way of doing it:

  1. get the latest blob name (1, 2, 3, … – natural numbers)
  2. append the block
  3. if (2) this throws:
    1. try to create the next one or retrieve existing one
    2. append the block

This allows multiple writers to write to the logically same chunked blob, that is split across multiple physical Append Blobs. Wait a minute, what about ordering?

Ordering multiple writers

With multiple writers A, B, C, … appending blocks

  1. A1, A2 – for A,
  2. B1, B2 – for B,
  3. C1, C3 – for C3

the following sequences could be a result of applying this approach:

  1. A1, A2, B1, B2, C1, C2
  2. A1, B1, B2, A2, C1, C2,
  3. A1, B1, B2, C1, C2, A2

You can see that this creates a partial order (A1 will always be before A2, B1 before B2, C1 before C2) but different total orders are possible, depending on the speed of writers. Usually, it’s just ok as the writers were appending to a blob their results, their operations, not carrying about the others’ results.

Summary

We’ve seen how easy it’s to implement a never ending append blob for multiple writers. This is a great enabler in case, where you need a single logical, log-like, blob, that provides an ordered list of blocks.

Pearls: Jil, serialization of primitives

The last pearl of design that I covered was an implementation for the discriminated union in the probuf-net library. Now, it’s time to move to an area that is less esoteric in terms of the format, but still intriguing in terms of performance. Time to take a look at the fastest JSON serializer available for .NET, Jil.

Is it fast?

Jil is crazy fast. As always, the best way to do something fast, is to skip some steps. You can think about skipping doing some computations, to effectively lower the load for the CPU. When speaking about programming in .NET, one additional thing to skip are allocations. And when speaking about allocations and JSON, the one that should come to our minds are strings. I don’t mean strings per se, but object that are transformed into them before writing to the actual input.

A unique case of GUID

GUID in .NET (or Guid) stands for Globally Unique Identifier. It’s a structure, 16 bytes long, providing a unique identity generator (let’s not deal with comb guids and other types for now). It’s frequently used whenever its the client responsibility to generate an id. It’s also cheap, as you don’t need to call the third party to get a globally unique id.

Let’s take a look how Guid is serialized by another library for .NET, probably, the most popular one, JSON.NET

As you can see above (and you can see it on GitHub), JSON.NET first calls .ToString, allocating  32 characters in a form of a string, just to pass it to the TextWriter instance. Yes, this instance will end its life shortly after writing it to the writer, but still, it will be allocated. What could be done better?

Jil to the rescue

We’ve got a text writer. If we had an additional buffer of char[] we could write characters from Guid to the buffer and then pass it to the text writer. Unfortunately, Guid does not provide a method to write its output to the buffer. Jil, provides one instead. It has an additional Guid structure that enables to access internal fields’ values of Guid. With this and a buffer, we can write to a text writer without allocating an actual string. The code is much to big to paste it in here. Probably it must be big to be that fast;-) Just follow this link to see the selected lines.

Summary

The mentioned optimization for Guid type is just one of many, that you can find in the awesome Jil library. As always, do not allocate, is one of the top commandments when talking about performance.

On reading whitepapers

There is an ancient technique that can help you in achieving mastery in computer science. No, I don’t mean a “from zero to hero in 2 hours” kind of online course. Nope, I don’t mean a free ebook that you can get after registering to a mailing list. Oh, some kind of a certification? I don’t mean it either. What I’m thinking about, is some real mental heavy lifting. I’m thinking about reading whitepapers.

It’s funny that wisdom can hit you after some time. I still remember words of one of my lecturers, who said, that it would be more beneficial for us to go home and study on our own, rather than listening to him. The very same can be applied to complex and/or innovative algorithms, processes, approaches described in whitepapers. Consider the new and shiny CosmosDB from Microsoft Azure. It promises indexing data in any schema (using JSON as a payload format). How can you achieve it, considering a multi-tenant environment (no, you’re not alone in the cloud) and all the funky objects stored in the database? Here’s the whitepaper describing it. Is it dense? Yes. Is it not-so-easy-to-read? Yes. Is it worth it? In my opinion, yes.

We live in times, when you can often face an assumption, that we need to ship things ASAP and understand them in a fast and easy way. Whitepapers are probably the exact opposite. It takes time to learn how to read them. It takes time to read every of them. It takes time to verify and apply findings in them.

I wish you more time, more focus, more presence and strength for spending it properly.

Pearls: the protobuf’s discriminated union

Google Protocol Buffers is a proven protocol for serializing data efficiently. It has a wide adoption, enabling serialization for almost every platform, making the data easy to exchange between platforms. To store its schema, you can use .proto files, that enable describing messages in a platform agnostic format. You can see an example below:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

One of

Sometimes you want to define a message that will have only one of its fields initialized. This can be useful when sending a message providing a wrap around multiple types or in any other case that requires it. Take a look at the example, providing a wrap around three messages of the following types: MessageA, MessageB and MessageC.

message Wrapper {
  oneof OnlyOneOf {
    MessageA a = 1;
    MessageB b = 2;
    MessageC c = 3;  
  }
}

Protocol buffers use a tag value to store any field. First, the tag (1, 2, 3 above) and the type of the field is stored, next, the value is written. In the following case, where only one field is assigned, it would write its tag, type and value. Do we need to create a class that will contain all the fields? Do we need to waste this space for storing fields?

Protobuf-net Discriminated Union

To fix this wasteful generation, protobuf-net, a library build by Marc Gravell, added Discriminated Union types that is capable of addressing it. Let’s just take a look at the first of them.

public struct DiscriminatedUnionObject
{
  private readonly int _discriminator;

 // The value typed as Object
 public readonly object Object;

 // Indicates whether the specified discriminator is assigned
 public bool Is(int discriminator) => _discriminator == ~discriminator;

 // Create a new discriminated union value
 public DiscriminatedUnionObject(int discriminator, object value)
 {
  _discriminator = ~discriminator; // avoids issues with default value / 0
  Object = value;
 }
}

Let’s walk through all the design choices that have been made here:

  1. DiscriminatedUnionObject is a struct. It means, that if a class have a field of this type, it will be stored in the object, without additional allocations (you can think of it as inlining the structure, creating a “fat object”)
  2. It has only one field for storing the value Object. (no matter which type is it).
  3. It has only one field, called _discriminator to store the tag of the field.

If you generated the Wrapper class, it’d have only one field, of the DiscriminatedUnionObject type. Once a message of a specified type is set, the discriminator and the value would be written in the union. Simple, and efficient.

Summing up

Mapping a generic idea, like a discriminated union, into a platform or a language isn’t simple. Again, once it’s made in an elegant and an efficient way, I truly believe that it’s worth to be named as a pearl.

The batch is dead, long live the smart batch

It lurks in the night. It consumes all the energy. It lasts much too long. If you experienced it, you know it’s unforgettable. If you’re lucky and you did not meet it, you probably heard these stories from your friends. Yes, I’m talking about the batch job.

The old batch

This ultimate tool of terror was dreading us for much too long. Statements like “let’s wait till tomorrow” or “I think that the job didn’t run” were quite popular a few years back. Fortunately for us, with the new waves of reactive programming, serverless and good old-fashioned queues, it’s becoming thing of the past. We’re in a very happy position being able to process events, messages, items as soon as they come into our system. Sometimes a temporary spike can be amortized by a queue. And it works. Until it’s not.

When working on processing 2 billion events per day with Azure functions, I deliberately started with the assumption of 1-1 mapping, where one event was mapped as one message. This didn’t go well (as planned). Processing 2 billion items can cost you a lot, even, if you run this processing on-premises, that are frequently treated as “free lunch”. The solution was easy and required going back to the original meaning of the batch, which is a group, a pack. The very same solution that can be seen in so many modern approaches. It was smart batching.

The smart batch

If you think about regular batching, it’s unbounded. There’s no limit on the size of the batch. It must be processed as a whole. Next day, another one will arrive. The smart batching is different. It’s meant to batch a few items in a pack, just to amortize different costs of:

  1. storage (accessing store once)
  2. transport (sending one package rather than 10; I’m aware of the Nagle’s algorithm)
  3. serialization (serializing an array once)

To use it you need:

  1. a buffer (potentially reusable)
  2. a timer
  3. potentially, an external trigger

It works in the following way. The buffer is a concurrent-friendly structure that allows appending new items by, potentially, multiple writers. Once

  1. the buffer is full or
  2. the timer fires or
  3. the external trigger fires

all the items that are in the buffer will be sent to the other party. This ensures that the flushing has:

  1. a bounded size (the size of the buffer)
  2. a bounded time of waiting for ack (the timer’s timeout)

With this approach, used actually by so many libraries and frameworks, one could easily overcome many performance related issues. It amortizes all the mentioned costs above, paying a bit higher tax, but only once. Not for every single item.

Outsmart your costs

The smart batch pattern enables you to cut lots of costs. For cloud deployments, doing less IO requests means less money spent on the storage. It works miracles for the throughput as well, no wonder that some cloud vendors allow you to obtain messages in batches etc. It’s just better.

Next time when you think about a batch, please, do it,  but in a smart way.

Podsumowanie roku 2017

Rok 2017 dobiega ku końcowi. Jak zawsze, to dobry czas na podsumowanie.

Prelekcje

Jeżeli chodzi o prelekcje dużego kalibru, to ten rok był bogatszy od poprzedniego. Na 13 wystąpień (lista), aż 9 to wystąpienia konferencyjne! Dwa wystąpienia, to wystąpienia szczególnie ważne: .NET Developers Days oraz DevConf. Na obydwu konferencjach prezentowałem Performance That Pays Off (lekko zmieniony), na obydwu mówiłem po angielsku. To pierwsze takie wystąpienia. W kolejnym roku mam nadzieję na więcej 🙂

Książki

Po przeczytaniu 20 pozabranżowych książek niefabularnych zdecydowanie odczuwam różnicę w postrzeganiu wielu spraw. 20 książek to niby nic, jednak starannie dobrana lektura daje bardzo dużo. Plan na kolejny rok? Zdecydowanie. Ten poziom trzeba utrzymać.

Blog

Na blogu pojawiło się więcej wpisów. Część, to serie, jak na przykład bardzo dobrze odebrany Top Domain Model czy materiały związane z Service Fabric. Część to wpisy tradycyjne.

Szkolenia

To pierwszy rok, w którym uruchomiłem kilka płatnych szkoleń z tematu, który pojawiał się wiele razy na tym blogu: Event Sourcing. W kolejnym roku planuję wyjść ze szkoleniami otwartymi poza Warszawę (np. Wrocław). Daty otwartych szkoleń, jak i opisy znajdziecie tutaj.

Open Source

Początek 2017 to sterownik .NETowy do PostgreSQL i Marten. Dzięki moim optymalizacjom biblioteka, która pozwala zamienić Wam PostgreSQL w bazę dokumentową z opcją Event Sourcingu, przyśpieszyła znacząco. Więcej: tutaj.

Niestety środek roku, to dwa projekty, które skorelowały się w czasie ze swego rodzaju wypaleniem. Obydwa dotyczyły Service Fabric, ostatni to Lockstitch.

Azure Functions

Cyklem blogowym, który zyskał najwięcej podań dalej oraz like’ów było przetwarzanie 2 miliardów pozycji dziennie przy użyciu Azure Functions. Temat ten, będzie przeze mnie kontynuowany w kolejnym roku w kilku formach:

  1. szkolenie z Azure Functions
  2. prelekcje (o tym niedługo więcej)
  3. X – o tym niedługo znacznie więcej

Podsumowanie

To był super rok. Kolejny, planowany powoli, z rozmysłem, zapowiada się jeszcze lepiej. Do siego!