MARV (part 4): Why Microsoft Orleans

MARV (part 4): Why Microsoft Orleans

[vers?o em português abaixo]

This is Part 4 of a series:


According to Carl Hewitt, message passing should have the same overhead as looping and procedure calling. This is a very tall order, as in that sentence there’s no room for memory synchronization, serialization, transport, location resolution, cluster management, and a lot of other problems that should be solved before the first message can be actually passed.

And, as stated earlier, we were already set with .NET as our weapon of choice.

Now, you may legitimately ask: given you had the Actor Model at the foundation of the concurrency model, how could you pick .NET even before talking about a .NET Actor Model Implementation?

Well, the truth about us and .NET is that we know the language (C#), its concurrency and memory model so deeply that building an Actor Model Implementation ourselves was always on the table. By the way, I already coordinated a project where we did exactly that. And that’s why this time I vowed to go straight up with MS Orleans, albeit with a very critical approach.

MS Orleans is very well structured and has some serious features. Also it’s community vision is very promising. 

I’ll talk about some pros and cons but, before that, there's 2 things I want to convey. 

First, some assertions, which are conceptually true for other .NET Actor Model implementations, like Akka.NET.

Second, a warning, about how MS Orleans API can contaminate every single code file you have on your solution, to the point you're stuck with MS Orleans for life.

Actor Model Invariants (on .NET)

  • An Actor is but a class, which implements a Well Known Interface, which in turn makes it possible for it to be addressable from anywhere in the Actor System.
  • The address of an Actor can be shipped away for remote use, and messages it’s capable of receiving can be strongly typed as parameters of the Well Known Interface methods.
  • By default, an Actor handles at most one message at a time, in a single threaded fashion. Messages sent to it while it’s busy get queued, and are delivered once it gets idle.
  • Actors have a life cycle, and can hook to it to recover state when they activate, for example.
  • The Actor System is composed of Nodes, with each Node hosting a set of Actor Activations (class + address). 
  • Nodes have a strategy to discover other Nodes and create consensus on how many Nodes are present and healthy, as well as vote unhealthy Nodes out of the Cluster.
  • You have to plan for the case when a Node hosting an Actor abruptly goes down. 

Choose Your Coupling

If you make a naive use of MS Orleans, then there’s a high chance you’ll end up with a few of these issues:

  • Every single code file, be it an actor, a message or a service will either extend a class, implement an interface or be decorated with an attribute from MS Orleans. This means the level of coupling between your business logic and MS Orleans API will be so high that jumping ship may become impractical.
  • Given MS Orleans has already a very low throughput, even a correct granularity of actors may lead to very poor performance due to message passing overhead.
  • If you don't disable Interleaving right from the beginning, the mono threaded peace of mind will be quickly gone, as a Task Continuation may find a different Actor state than that which existed when the Task Await started.

Countering the above concerns is not trivial, and right from the beginning we had a very critical approach to MS Orleans.

Basically, we approached MS Orleans as if we needed to be able to replace it down the line without having to rewrite the solution. This means no usage of storage, actor versioning or message versioning, and no relying on lots of other features. 

Also we were not able to use MS Orleans Streams, as they do not provide for decoupling between Actors, and instead lead to even more coupling with MS Orleans itself (more on that in a moment, and on the next piece).

Now, for the pros and cons of MS Orleans, according to our experience.

Pro #1: The Grain Directory

Orleans Grain Directory job is to keep track of which Actor (Grain in Orleans speak) is running in which Node (Silo). The Grain Directory is updated every time an Actor activates or deactivates.

It is sophisticated enough to allow for different storage providers (like the Redis one we are using) and has a killer feature: custom Actor placement. 

With custom Actor placement, very efficient topologies can be structured:

  • The total number of passed messages can be reduced, as a single message from a remote silo can be distributed for multiple local Actors
  • Local Actors can share services and utilities, making it very easy to convert the communication to other protocols, like a HTTP API, when necessary.
  • You can prevent an Actor from being (re)activated on “the wrong” Silo, when its original Silo went down and some other Actor tries to communicate with it.

Yet, when no location affinity is needed, you can count on Orleans default random placement to achieve some balance on the load between all Silos than can host that Actor Type.

Pro #2: Cluster Management

Silos join and exit the Cluster in an organized, predictable way. You can subscribe to any cluster change, and rewire (or cleanup) any Actor relationship that may have been lost.

When a Silo goes bad, other Silos will quickly vote it out of the cluster and cut communications to it. When the bad Silo learns about this, it will shut itself down (with a somewhat funny message) . 

If the deployment has some orchestration (e.g K8s), the Silo will come back up again, with the potential for full auto healing of the Cluster. 

Cluster Management, as well as several other aspects of MS Orleans, continues to be improved.

Pro #3: Full Type Checking

MS Orleans leverages the Roslyn Compilation Pipeline to hardwire all possible message paths, along with their serializers. This allows for full type checking during design and compile time.

When troubleshooting, all generated code can be checked upon, and that cannot be overstated. 

Pro #4: Great Support From The Community

MS Orleans has lots of features, covers a lot of use cases, is technically very complex and is moving quite fast. That makes it very hard to document.

Our project however, would not be the same without the tireless support of Orleans community members, specially Microsoft Orleans Lead, Reuben Bond.

Pro #5: Still In Heavy Development

The vision for MS Orleans is very promising, and at least from our perspective, most of its shortcomings are to be addressed in the next major release (4.0).

There’s also a lot of synergy with the late developments of .NET and C# in general.. 

Con #1: Low Throughput 

Don’t get me wrong! It's perfectly possible to have thousands of Actors in dozens of Silos exchanging millions of messages per second, in aggregate. 

And that’s the beauty of Actor Model. Carl Hewitt once joked that high overhead would not stop us from succeeding, because of the exponential growth of the core count. And the joke aside, even 50% overhead on (local ordered) message passing would still net us roughly 10M calls per second.

However, if we talk about how many messages we can get from Actor A to Actor B, MS Orleans has about this throughput:

No alt text provided for this image

Ouch! 3K messages a second for remote synchronous ordered calls. That alone would have blocked us from ever using MS Orleans. More on that in our next piece.

However, If you think about it, 3K ordered sync remote messages per second is actually impressive. The problem for that scenario is that MS Orleans is more a Distributed .NET implementation than a strict Actor Model implementation. Also, there is no such mode as Async Ordered messaging. 

This means an ordered call is equivalent to a ping, in the sense that it not only pipes the request to the target, but also has to pipe the return to the caller, even if that return is only a completed Task. While this provides for exceptions to explode on the call site, which is very intuitive for .NET developers, it also eats up a lot of throughput.

The issue here is that sequenced communication is not a first class citizen and seems to be but a side effect of synchronous messaging. Out of the box there’s no way to have sequenced messaging without awaiting that call, with the negative effect of never being able to saturate neither the transport nor the scheduling layers.

But even if MS Orleans went the dead letter way to allow for exception handling without that await, there’s still other hurdles to sequencing. First, the way MS Orleans schedules message delivery is non deterministic, and some rerouting scenarios will always make room for ordering issues (in the current implementation).

The solution to this problem however, is within reach, for MS Orleans is flexible and powerful enough to allow for communication abstractions on top of its current implementation.

I'll elaborate on that in the next pieces.

Overall, MS Orleans also suffers from having a lot of use cases to support and, most of all, from having its core written with no concern for heap allocations, as was the case with most things .NET a couple years ago.

Con #2: Streams Are An Afterthought

We chose to embrace stateful actors as Single Sources of Truth for their respective identities. This means state has to be constantly updated with changes, so when a transaction has to go through, no I/O (data shipping) is needed to complete it.

MS Orleans Streams may sound like the perfect solution for organizing that flow of messages, without having every actor coupled with every other. But that’s not the case.

  • The Stream ID (which the publisher has to know) must be the same as the Subscriber’s ID (coupling #1)
  • The .NET Type that flows through the stream has to be known by both publisher and subscriber (coupling #2)
  • Heterogeneous Clusters (silos that can activate different Actors) are not supported

Most of the story about why Streams are not great is on this github issue.

Con #3: Serializers are Unforgiving

Include or remove a property on the model you are shipping the other silo and that's it. Everything is broken unless you update and redeploy all Silos.

This makes for very difficult management of changes and deploys.

Con #4: Error Logs Do Not Always Help

Sometimes errors will get logged like this:

Cannot enqueue message to invalid activation [Activation: S100.96.160.2:57700:342932477*grn/E4153DE7/0000000000000000000000000000000006283bd1e4153de7+apex-batch-miss|Sales-342932477-0x76EAC04D@49f8329f #GrainType=Marv.Apex.Abstractions.InternalProxyGrain`2[[Marv.Apex.GrainInterfaces.IStateSubjectGrain, Marv.Apex.Abstractions, Version=4.4.0.0, Culture=neutral, PublicKeyToken=null],[Marv.Apex.Messages.ApexBatchMiss, Marv.Apex.Abstractions, Version=4.4.0.0, Culture=neutral, PublicKeyToken=null]] Placement=SpaceTimePlacement State=Invalid NonReentrancyQueueSize=0 EnqueuedOnDispatcher=0 InFlightCount=0 NumRunning=0 IdlenessTimeSpan=737741.03:19:33.5387898 CollectionAgeLimit=32767.00:00:00] : NewPlacement Request S100.96.64.1:57100:342931074*grn/8ADC530C/00000000+apex-batch-miss@f712ab9f->S100.96.160.2:57700:342932477*grn/E4153DE7/00000000+apex-batch-miss|Sales-342932477@49f8329f #96830{"EventId": {"Id": 101538}, "SourceContext": "Orleans.Runtime.ActivationData", "Version": "1.0.0.0", "Jornada": "risco-Sales", "ClusterId": "172.20.0.1", "ClusterHash": "4FE6"}


That makes it very hard to reason about the relationship between such log entries and any undesired behavior or failure, let alone move towards a solution.

It would be better if MS Orleans did not try to solve everything by its own and embraced the explicit externalization of communication incidents by design. That way we could more easily plan and work around the most commonly expected failures, like an Actor being unreachable or a message being dropped or reaching its handling timeout.

Con #5: Out of The Box Configs Are Inconsistent

Orleans provides for C# that can be remotely executed with full location transparency. Despite some limitations on .NET generic awesomeness and some obvious limits on the parameters than can be passed (please don’t ship a delegate to another Silo), we may be led to believe that a class (Grain) would by default behave like any class would: 

  1. It’s method calls would hang until complete, unless we wrapped the call in an awaitable timeout and managed ourselves said timeout. 
  2. Once created, the class would be safe from garbage collection until we explicitly cleared any reference to it.

Well, none of that is true by default. And that takes a lot of unnecessary time to figure out.

You see, Orleans is already parting ways with a strict Actor Model implementation here, as the default method call with a return value breaks the temporal decoupling principle. Then, why not go full tilt and just emulate all of .NET semantics, including class lifecycle and method calls?

I already feel bad for making that critique. Maybe that's because I'm both a dreamer and fully aware of the incredible and awesome job the MS Orleans team has done so far.

Working Around The Cons

I'll just quickly list the directions we followed to mitigate the pain points above.

For the most part, next pieces of this series will elaborate on the important bits.

  1. Low Throughput: we solved that by writing a broadcast protocol on top of MS Orleans communication that allows for 1M ordered asynchronous messages per second between any two Actors.
  2. Streams are an Afterthought: we solved that by building a message broker on top of MS Orleans that allows for full pub sub decoupling and also solves the late joiner problem. We also handled the cache miss fallback while we were at it. We called it Apex and will soon open source it.
  3. Serializers Are Unforgiving: we solved that by defining an envelope that holds a serialized payload, along with routing information: Type, Topic and SubTopic. The payload is serialized with System.Text.Json, and as long as the envelope itself does not change, the versioning gates of hell stay shut.
  4. Error Logs Are Not Helpful: We are in the process of figuring that out, and whether there are failure modes from which it is too hard to recover without it.
  5. Configs Are Inconsistent: we just dealt with it. Overcome and adapt, remember?

In that process Bruno Cupertino, Gustavo Silva and Marcos Venezuela contributions were key to our discussions and insight, as well as the support of Mr Reuben Bond, Benjamin Petit and Kevin Cathcart.

In the next piece, I'll discuss Easynvest’s Apex, which solved pub sub on top of MS Orleans, with enough thruput to handle 50K messages per second with only 5% overhead, that is, we can pipe through 50K messages per second and still be 95% idle.

See you next time!

----------------------------

Por Que Microsoft Orleans?

Esta é a parte 4 de uma série:

De acordo com Carl Hewitt, a passagem de mensagens deve ter o mesmo custo que la?o e chamada de método. Esta é uma exigência muito cruel, pois nessa frase n?o há espa?o para sincroniza??o de memória, serializa??o, transporte, resolu??o de localiza??o, gerenciamento de clusters e muitos outros problemas que devem ser resolvidos antes que a primeira mensagem possa ser realmente passada.

E, como dito anteriormente, já tínhamos definido que o .NET é nossa arma de escolha.

Agora, você pode legitimamente perguntar: dado que você tinha o Modelo de Ator na base do modelo de concorrência, como você poderia escolher .NET mesmo antes de falar sobre uma implementa??o de Modelo de Ator em .NET?

Bem, a verdade sobre nós e o .NET é que conhecemos a linguagem (C#), seu modelo de concorrência e modelo de memória t?o profundamente que construir uma implementa??o modelo de ator nós mesmos sempre foi uma op??o. A propósito, eu já coordenei um projeto onde fizemos exatamente isso. E é por isso que desta vez eu votei por ir direto com o MS Orleans, embora com uma abordagem muito crítica.

MS Orleans é muito bem estruturado e tem algumas funcionalidades muito valiosas. Além disso, a vis?o de futuro de sua comunidade é muito promissora. 

Falarei sobre alguns prós e contras, mas, antes disso, há 2 tópicos que quero estabelecer. 

Primeiro, algumas afirma??es, que s?o conceitualmente verdadeiras para outras implementa??es .NET do Actor Model, como Akka.NET.

Segundo, um aviso sobre como a API do MS Orleans pode contaminar cada arquivo de código que você tem em sua solu??o, ao ponto de você ficar preso ao MS Orleans para sempre.

Invariantes do Modelo de Ator (em .NET)

  • Um ator é apenas uma classe, que implementa uma Interface Bem Conhecida, o que, por sua vez, torna possível que ele seja endere?ado de qualquer lugar do Sistema de Atores.
  • O endere?o de um ator pode ser enviado para uso remoto, e as mensagens que ele é capaz de receber podem ser fortemente tipadas como parametros dos métodos de Interface Bem Conhecidos.
  • Por padr?o, um ator lida no máximo com uma mensagem de cada vez, de uma forma mono thread. Mensagens enviadas a ele enquanto ele está ocupado ficam na fila, e s?o entregues uma vez que fica ocioso.
  • Os atores têm um ciclo de vida, e podem ser notificados sobre ele para recuperar o estado quando eles ativam, por exemplo.
  • O Sistema de Ator é composto por Nós, com cada Nó hospedando um conjunto de Ativa??es de Atores (classe + endere?o). 
  • Os nós têm uma estratégia para descobrir outros Nós e criar consenso sobre quantos Nós est?o presentes e saudáveis, bem como votar Nós n?o responsivos ou instáveis para fora do Cluster.
  • Você tem que planejar o caso no qual um nó que hospeda um ator ator cai abruptamente. 

Escolha seu Acoplamento

Se você fizer um uso ingênuo da MS Orleans, ent?o há uma grande chance de você acabar com alguns desses problemas:

  • Cada arquivo de código, seja um ator, uma mensagem ou um servi?o, estenderá uma classe, implementará uma interface ou será decorado com um atributo do MS Orleans. Isso significa que o nível de acoplamento entre sua lógica de negócios e a API de MS Orleans será t?o alto que sair do MS Orleans no futuro pode ser impossível.
  • Dado que MS Orleans já tem uma vaz?o muito baixa, mesmo uma granularidade correta dos atores pode levar a um desempenho muito ruim devido ao custo da passagem de mensagens.
  • Se você n?o desativar o Interleaving desde o início, a paz de espírito mono-threaded desaparecerá rapidamente, pois uma continua??o de Task pode encontrar um estado de ator diferente do que existia quando o Await da Task come?ou.

Sanar as preocupa??es acima n?o é trivial, e desde o início tivemos uma abordagem muito crítica com o MS Orleans.

Basicamente, nós abordamos o Orleans como se precisássemos substituí-lo sem ter que reescrever a solu??o. Isso significa que n?o há uso de armazenamento, versionamento da interface do ator ou da mensagem, e n?o dependemos de quase nenhuma funcionalidade do MS Orleans. 

Também n?o foi possível usar as MS Orleans Streams, pois elas n?o permitem o desacoplamento entre atores, e em vez disso levam a ainda mais acoplamento com o próprio MS Orleans (mais sobre isso no abaixo, e na próxima pe?a).

Agora, para os prós e contras de MS Orleans, de acordo com nossa experiência.


Pro #1: O Diretório de Grains

O trabalho do Diretório de Grains do Orleans é acompanhar qual ator (Grain no vernáculo do Orleans) está executando em qual Node (Silo). O Diretório de Grains é atualizado toda vez que um ator ativa ou desativa.

Ele é sofisticado o suficiente para permitir diferentes provedores de armazenamento (como o Redis que estamos usando) e tem um recurso matador: Custom Actor Placement. 

Com a coloca??o customizada do ator, topologias muito eficientes podem ser estruturadas:

  • O número total de mensagens passadas pode ser reduzido, pois uma única mensagem de um silo remoto pode ser distribuída para vários atores locais. 
  • Os atores locais podem compartilhar servi?os e utilitários, tornando muito fácil converter a comunica??o em outros protocolos, como uma API HTTP, quando necessário.
  • Você pode impedir que um ator seja (re)ativado no Silo "errado", quando seu Silo original caiu e algum outro ator tenta se comunicar com ele.

No entanto, quando nenhuma afinidade de localiza??o é necessária, você pode contar com a coloca??o aleatória padr?o de Orleans para obter algum equilíbrio na carga entre todos os Silos do que pode hospedar esse Tipo de Ator.

Pro #2: Gerenciamento de Clusters

Silos entram e saem do Cluster de forma organizada e previsível. Você pode assinar qualquer altera??o de cluster e religar (ou limpar) qualquer rela??o de ator que possa ter sido perdida.

Quando um Silo vai mal, outros Silos rapidamente o votar?o para fora do cluster e cortar?o as comunica??es para ele. Quando o Silo ruim descobrir que foi excluído, ele vai se desligar (com uma mensagem um tanto engra?ada) . 

Se a implanta??o tiver alguma orquestra??o (por exemplo K8s), o Silo voltará a subir novamente, com potencial para a recupera??o automática completa do Cluster. 

A gest?o de clusters, bem como vários outros aspectos de MS Orleans, continua a ser melhorada.

Pro #3: Full Type Checking

MS Orleans aproveita o Roslyn Compilation Pipeline para ligar todos os caminhos de mensagens possíveis, juntamente com seus serializers. Isso permite a verifica??o completa do tipo durante o projeto e o tempo de compila??o.

Ao solucionar problemas, todo o código gerado pode ser verificado, e isso tem um valor imenso. 

Pró #4: Grande apoio da comunidade

MS Orleans tem muitas características, cobre muitos casos de uso, é tecnicamente muito complexo e está se movendo muito rápido. Isso torna muito difícil documentar.

Nosso projeto, no entanto, n?o seria o mesmo sem o apoio incansável dos membros da comunidade MS Orleans, especialmente o Líder do Microsoft Orleans, Reuben Bond.

Pro #5: Ainda em Desenvolvimento Pesado

A vis?o para MS Orleans é muito promissora, e pelo menos do nosso ponto de vista, a maioria de suas deficiências devem ser abordadas no próximo grande lan?amento (4.0).

Há também muita sinergia com os desenvolvimentos recentes do .NET e C# em geral.. 

Con #1: Baixa Vaz?o

N?o me entenda mal! é perfeitamente possível ter milhares de atores em dezenas de Silos trocando milh?es de mensagens por segundo, no agregado. 

E essa é a beleza do Actor Model. Carl Hewitt uma vez brincou que o custo alto n?o nos impediria de ter sucesso, em fun??o do crescimento exponencial da quantidade de núcleos de CPU. E piada à parte, mesmo 50% de custo sobre passagem de mensagens (local ordenado) ainda nos renderia cerca de 10 Milh?es de chamadas por segundo.

No entanto, se falarmos sobre quantas mensagens podemos obter de Ator A para Ator B, MS Orleans tem um rendimento próximo de:

No alt text provided for this image

Uau! 3K Mensagens por segundo para chamadas remotas e síncronas. Só isso nos impediria de usar o MS Orleans. Mais sobre isso na nossa próxima pe?a.

No entanto, se você pensar sobre isso, 3K dessa forma é até impressionante. O problema para esse cenário é que o MS Orleans é mais uma implementa??o distribuída .NET do que uma implementa??o rigorosa do Modelo de Ator. Além disso, n?o existe um modo nativo de enviar mensagens ordenadas de modo assíncrono. 

Isso significa que uma chamada ordenada é equivalente a um ping, no sentido de que ela n?o apenas envia a solicita??o para o alvo, mas também tem que recuperar o retorno para o chamador, mesmo que esse retorno seja apenas uma Task.CompletedTask. Embora isso possibilite que exceptions explodam no local das chamadas, o que é muito intuitivo para desenvolvedores .NET, esta característica vem acompanhada de uma enorme penalidade na vaz?o.

A quest?o aqui é que a comunica??o sequenciada n?o é um cidad?o de primeira classe e parece ser apenas um efeito colateral das mensagens síncronas. Por padr?o, n?o há como ter mensagens sequenciadas sem esperar essa chamada, com o efeito negativo de nunca ser capaz de saturar nem o transporte nem as camadas de agendamento.

Mas mesmo que o MS Orleans fosse na dire??o de ter um mecanismo dead letter, ainda há outros obstáculos para mensagens sequenciadas. Primeiro, a forma como o MS Orleans programa a entrega de mensagens n?o é determinística, e alguns cenários de redirecionamento sempre abrir?o espa?o para problemas de sequência (na implementa??o atual).

A solu??o para este problema, no entanto, está ao alcance, pois o MS Orleans é flexível e poderoso o suficiente para permitir abstra??es de comunica??o em cima de sua implementa??o atual.

Vou elaborar isso nas próximas pe?as.

No geral, o MS Orleans também sofre por ter muitos casos de uso para apoiar e, acima de tudo, de ter seu núcleo escrito sem preocupa??o com aloca??es de heap, como foi o caso da maioria das coisas em .NET alguns anos atrás.

Con #2: Streams s?o uma adi??o posterior

Optamos por usar atores stateful como Fontes únicas da Verdade para suas respectivas identidades. Isso significa que o estado tem que ser constantemente atualizado com altera??es. Portanto, quando uma transa??o tem que passar, n?o é necessário I/O (envio de dados) para completá-la.

MS Orleans Streams pode soar como a solu??o perfeita para organizar esse fluxo de mensagens, sem ter todos os atores juntamente com todos os outros. Mas esse n?o é o caso.

O ID do Stream (que o publicador tem que saber) deve ser o mesmo do ID do Assinante (acoplamento #1)

O tipo .NET que flui através do fluxo deve ser conhecido tanto pelo editor quanto pelo assinante (acoplamento #2)

Clusters heterogêneos (silos que podem ativar diferentes atores) n?o s?o suportados

A maior parte da história sobre por que streams n?o s?o legais está nesta issue do github.

Con #3: Serializers S?o Crueis

Inclua ou remova uma propriedade no modelo que você está enviando o outro silo e é isso. Tudo está quebrado a menos que você atualize e reimplante todos os Silos.

Isso torna uma gest?o muito difícil de mudan?as e implanta??es.

Con #4: Registros de erros nem sempre ajudam

às vezes, erros s?o registrados assim:

Cannot enqueue message to invalid activation [Activation: S100.96.160.2:57700:342932477*grn/E4153DE7/0000000000000000000000000000000006283bd1e4153de7+apex-batch-miss|Sales-342932477-0x76EAC04D@49f8329f #GrainType=Marv.Apex.Abstractions.InternalProxyGrain`2[[Marv.Apex.GrainInterfaces.IStateSubjectGrain, Marv.Apex.Abstractions, Version=4.4.0.0, Culture=neutral, PublicKeyToken=null],[Marv.Apex.Messages.ApexBatchMiss, Marv.Apex.Abstractions, Version=4.4.0.0, Culture=neutral, PublicKeyToken=null]] Placement=SpaceTimePlacement State=Invalid NonReentrancyQueueSize=0 EnqueuedOnDispatcher=0 InFlightCount=0 NumRunning=0 IdlenessTimeSpan=737741.03:19:33.5387898 CollectionAgeLimit=32767.00:00:00] : NewPlacement Request S100.96.64.1:57100:342931074*grn/8ADC530C/00000000+apex-batch-miss@f712ab9f->S100.96.160.2:57700:342932477*grn/E4153DE7/00000000+apex-batch-miss|Sales-342932477@49f8329f #96830{"EventId": {"Id": 101538}, "SourceContext": "Orleans.Runtime.ActivationData", "Version": "1.0.0.0", "Jornada": "risco-Sales", "ClusterId": "172.20.0.1", "ClusterHash": "4FE6"}


Isso torna muito difícil raciocinar sobre a rela??o entre tais entradas de registro e qualquer comportamento ou fracasso indesejado, muito menos avan?ar em dire??o a uma solu??o.

Seria melhor se a MS Orleans n?o tentasse resolver tudo por conta própria e abra?asse a externaliza??o explícita dos incidentes de comunica??o por design. Dessa forma, poderíamos planejar e contornar mais facilmente as falhas mais esperadas, como um ator ser inalcan?ável ou uma mensagem sendo descartada ou atingindo seu tempo limite de execu??o.

Con #5: Configs Padr?o S?o Inconsistentes

Orleans fornece c# que pode ser executado remotamente com transparência completa de localiza??o. Apesar de algumas limita??es na funcionalidade genérica .NET e alguns limites óbvios sobre os parametros que podem ser passados (por favor, n?o envie um delegate para outro Silo), podemos ser levados a acreditar que uma classe (Grain) se comportaria por padr?o como qualquer classe: 

  • Suas chamadas de método ficariam penduradas até completar, a menos que embrulhamos a chamada em um tempo limite aguardado e nos gerenciamos com o tempo limite. 
  • Uma vez criada, a classe estaria a salvo da coleta de lixo até limparmos explicitamente qualquer referência a ela.

Bem, nada disso é verdade por padr?o. E isso leva muito tempo para descobrir.

Você vê, Orleans já n?o é uma implementa??o rigorosa do Modelo de Ator, já que o método padr?o de chamada com um valor de retorno quebra o princípio de dissocia??o temporal. Ent?o, por que n?o emular todas as semanticas .NET, incluindo ciclo de vida de classe e chamadas de método?

Já me sinto mal por fazer essa crítica. Talvez seja porque sou um sonhador e plenamente consciente do incrível trabalho que a equipe do MS Orleans fez até agora.


Trabalhando em torno dos contras

Vou listar rapidamente as dire??es que seguimos para mitigar os pontos de dor acima.

Na maior parte do tempo, as próximas pe?as desta série ir?o elaborar sobre os trechos importantes.

  • Baixo rendimento: resolvemos isso escrevendo um protocolo de transmiss?o em cima da comunica??o de MS Orleans que permite mensagens assíncronas ordenadas 1M por segundo entre os dois Atores.
  • Streams s?o uma reflex?o posterior: resolvemos isso construindo um corretor de mensagens no topo de MS Orleans que permite o desacoplamento completo do publicador e consumidor e também resolve o problema do late joiner. Nós também lidamos com o cache miss recuo enquanto estávamos nele. Nós o chamamos de Apex e em breve abriremos o código.
  • Serializers S?o Crueis: resolvemos isso definindo um envelope que contém uma carga serializada, juntamente com informa??es de roteamento: Tipo, Tópico e SubTopic. A carga é serializada com System.Text.Json, e enquanto o envelope em si n?o mudar, os port?es do inferno do versionamento permanecem fechados.
  • Registros de erros n?o s?o úteis: Estamos no processo de descobrir isso e se há modos de falha dos quais é muito difícil recuperar sem ele.
  • Configs s?o inconsistentes: apenas lidar com isso. Superar e adaptar, lembra?

Nesse processo, as contribui??es de Bruno Cupertino, Gustavo Silva e Marcos Venezuela foram fundamentais para nossas discuss?es e insights, bem como para o apoio de Reuben Bond, Benjamin Petit e Kevin Cathcart.

Na próxima parte, discutirei o Apex da Easynvest, que resolveu o pub sub em cima do MS Orleans, com o suficiente para lidar com 50K mensagens por segundo com apenas 5% de custo, ou seja, podemos passar 50K mensagens por segundo e ainda ficar 95% ociosos.

Até a próxima!

Mickael Thumerel

AI Solution Builder

1 年

We have develop a layer above Orleans call Democrite (https://github.com/Nexai-net/democrite). This orchestrator framework allow grain to be developed separately without usage knowledge and at the end you use trigger, sequence and signal to process you flow of information.

要查看或添加评论,请登录

Thiago Almeida的更多文章

  • MARV (part 3): Why Actor Model?

    MARV (part 3): Why Actor Model?

    [vers?o em português abaixo] This is Part 3 of a series: Part 1: MARV: Horizontally Scalable Low Latency Real Time…

    1 条评论
  • MARV (part 2): Why .NET?

    MARV (part 2): Why .NET?

    [vers?o em português abaixo] This is Part 2 of a series: Part 1: MARV: Horizontally Scalable Low Latency Real Time…

    1 条评论
  • MARV: Horizontally Scalable Low Latency Real Time Processing

    MARV: Horizontally Scalable Low Latency Real Time Processing

    #NET, #ActorModel, #K8s [vers?o em português abaixo] Intro (the context and the mission) Brazil’s electronic trading…

    4 条评论

社区洞察

其他会员也浏览了