Primeiros passos com Akka


Uma série de artigos sobre o framework Lock Free:

1 O que é Akka?

Akka é um kit de ferramentas e tempo de execução para a construção de aplicativos de alta concorrência, distribuídos e tolerantes a falhas na plataforma de máquina virtual JAVA. Akka é escrito na linguagem Scala e também fornece interfaces de desenvolvimento para Scala e Java.

A maneira como a Akka lida com a simultaneidade é baseada no modelo de ator.

Actor的概念来自于Erlang,在AKKA中,可以认为一个Actor就是一个容器,用以存储状态、行为、Mailbox以及子Actor与Supervisor策略。Actor之间并不直接通信,而是通过Mail来互通有无。

在Actor模式中,每个Actor都有一个(恰好一个)Mailbox。Mailbox相当于是一个小型的队列,一旦Sender发送消息,就是将该消息入队到Mailbox中。入队的顺序按照消息发送的时间顺序。Mailbox有多种实现,默认为FIFO。但也可以根据优先级考虑出队顺序,实现算法则不相同。

A estrutura akka consiste nas seguintes partes:

akka-atores

O núcleo do Akka, um modelo para simultaneidade e distribuição, sem toda a dor dos primitivos de thread

Akka-stream

Uma maneira intuitiva e segura de obter processamento de refluxo de pressão assíncrono e sem bloqueio.

Akka-http

Cliente e servidor HTTP de streaming moderno, rápido, assíncrono.

akka-cluster

Ganhe resiliência e resiliência distribuindo seu sistema em vários nós.

fragmentação de Akka

De acordo com a identidade do usuário, atribua seus participantes no cluster.

Dados Distribuídos

Eventualmente consistente, altamente disponível para leitura e gravação e dados de baixa latência

Persistência Akka

O pacote de eventos para participantes permite que eles alcancem o mesmo estado após reiniciar.

Gestão Akka

Execute extensões do sistema Akka no sistema em nuvem (k8s, aws, ...)

Alpaca

Akka Streaming Connector é usado para integrar outras tecnologias

2 recursos Akka:

  • Uma abstração mais alta do modelo de simultaneidade

  • É um modelo de programação assíncrono, não bloqueador e orientado a eventos de alto desempenho

  • Processamento leve de eventos (1 GB de memória pode conter milhões de atores)

  • Ele fornece um modelo de simultaneidade chamado Actor, que tem uma granularidade menor do que os encadeamentos, e você pode habilitar um grande número de Atores no sistema.

  • Ele fornece um conjunto de mecanismos tolerantes a falhas, permitindo algumas operações de recuperação ou reinicialização quando o Ator está anormal.

  • A Akka pode construir programas altamente simultâneos em uma única máquina ou construir programas distribuídos na rede e fornecer serviços de localização de Ator transparentes para a localização.

Modelo de 3 atores

Em um programa concorrente, um thread é a unidade básica de execução de um programa concorrente, mas na Akka, a unidade de execução é um Ator. O modelo Actor é um modelo de programação concorrente distribuída proposto em 1973, e é amplamente suportado e aplicado na linguagem Erlang.

No modelo Actor, em vez de dizer ao Actor o que fazer por meio de um método do objeto Actor, ele envia uma mensagem ao Actor. Quando um ator recebe uma mensagem, ele pode realizar determinadas ações com base no conteúdo da mensagem, como a mudança de seu próprio estado.Neste momento, a mudança desse estado é feita pelo próprio ator e não por intervenção externa.

Em Erlang, cada pedaço de código é executado em um processo. O processo é o nome de Actor em Erlang , o que significa que seu estado não afeta outros processos. Haverá um supervisor no sistema, que na verdade é apenas mais um processo. Quando o processo monitorado travar, o supervisor será notificado e atendido, para que um sistema com função de autocorreção também possa ser criado. Se um ator atingir um estado anormal e travar, não importa o que aconteça, o supervisor pode reagir e tentar torná-lo em um estado consistente.A forma mais comum é reiniciar o ator de acordo com o estado inicial.


简单来说,Actor通过消息传递的方式与外界通信,而且消息传递是异步的。每个Actor都有一个邮箱,邮箱接收并缓存其他Actor发过来的消息,通过邮箱队列mail queue来处理消息。Actor一次只能同步处理一个消息,处理消息过程中,除了可以接收消息外不能做任何其他操作。

Cada ator é totalmente independente e pode realizar suas operações ao mesmo tempo. Cada ator é uma entidade de computação que mapeia as mensagens recebidas e executa as seguintes ações: enviar um número limitado de mensagens a outros atores, criar um número limitado de novos atores e especificar o comportamento da próxima mensagem recebida. Essas três ações não têm ordem fixa e podem ser executadas concomitantemente, sendo que o Ator realizará diferentes processamentos de acordo com a mensagem recebida.

3.1 Vantagens do Modelo de Ator


传统并发程序是基于面向对象的方法,通过对象的方法调用进行信息传递,如果对象的方法修改对象本身的状态,在多线程下就可能出现对象状态的不一致,此时就必须对方法调用进行同步,而同步操作会牺牲性能。

Por exemplo, quando dois threads tentam comprar o último item ao mesmo tempo, se não houver bloqueio, vários threads podem determinar simultaneamente que o valor do contador é maior ou igual ao número de compras e, em seguida, diminuir incorretamente o contador, resultando em um número negativo e problemas de segurança de thread.

Para evitar problemas de segurança de thread, bloqueios são necessários.

Tomando o uso de bloqueios leves do Java como a coluna, no estágio altamente competitivo, há uma fila de encadeamentos muito longa e todos eles estão aguardando o contador de decréscimo. Mas o problema com a forma de usar filas é que ela pode causar muitos threads bloqueados, ou seja, cada thread está aguardando sua vez para realizar uma operação serializada.

Portanto, o uso irracional de bloqueios provavelmente transformará um aplicativo multi-core e multi-thread em um aplicativo de thread único ou causará um alto grau de competição entre os threads de trabalho .

O modelo Actor resolve esse problema com elegância e fornece um suporte básico para aplicativos verdadeiramente multithread.

3.2 Responsabilidades das funções do ator:

O modelo de ator abstrai tudo no sistema em uma função de ator. Em um sistema, uma tarefa em grande escala pode ser decomposta em algumas tarefas pequenas. Essas pequenas tarefas podem ser processadas simultaneamente por vários atores, reduzindo assim o tempo de conclusão da tarefa.

Em resposta a uma mensagem recebida, um ator pode tomar algumas decisões por conta própria, como criar mais atores, enviar mais mensagens ou determinar como responder à próxima mensagem recebida.

Responsabilidades das funções do ator:

  • A entrada do ator é a mensagem recebida

  • O ator recebe a mensagem e decide como lidar com ela: como criar mais atores, ou enviar mais mensagens, ou determinar como responder à próxima mensagem recebida

  • Os atores podem enviar mensagens a outros atores após a conclusão das tarefas

Uma vantagem do modelo de Ator é que o estado compartilhado pode ser eliminado: os atores podem processar apenas uma mensagem por vez, portanto, os atores podem processar o estado interno com segurança, independentemente do mecanismo de bloqueio.

No modelo Ator, o protagonista é um ator, que se assemelha a um trabalhador. Os atores enviam mensagens diretamente entre si, sem qualquer intermediário. As mensagens são enviadas e processadas de forma assíncrona. No modelo Ator, tudo é um Ator, e todas as lógicas ou módulos podem ser considerados Atores. A comunicação e a interação entre os módulos são realizadas através da passagem de mensagens entre diferentes Atores.

O ator é composto de estado, comportamento e caixa de correio .

  • Estado: Estado refere-se às informações variáveis ​​do objeto ator.O estado é gerenciado pelo próprio ator para evitar problemas como bloqueios e atomicidade da memória em um ambiente concorrente.

  • Comportamento (comportamento): O comportamento especifica a lógica de cálculo no ator e altera o estado do ator por meio da mensagem recebida pelo ator.

  • Caixa de correio: a caixa de correio é a ponte de comunicação entre os atores.A fila de mensagens FIFO é usada para armazenar e enviar mensagens dentro da caixa de correio, e o destinatário obtém as mensagens da caixa de correio.

3.3 Responsabilidades da função de caixa de correio

Um ator sozinho não é suficiente, vários atores podem formar um sistema. No modelo de Ator, cada ator tem seu próprio endereço, portanto, eles podem enviar mensagens uns aos outros. Algo a ser destacado é que, embora vários atores estejam em execução ao mesmo tempo, um só pode processar mensagens sequencialmente. Em outras palavras, quando outros atores enviam várias mensagens a um ator, o ator só pode processar uma de cada vez. Se você precisar processar várias mensagens em paralelo, precisará enviar as mensagens para vários atores.

As mensagens são enviadas ao ator de forma assíncrona, portanto, quando o ator está processando a mensagem, a nova mensagem deve ser armazenada em outro lugar, que é o local onde a mensagem da caixa de correio é armazenada.

Cada ator tem uma e apenas uma caixa de correio. A caixa de correio é equivalente a uma pequena fila. Assim que o remetente envia uma mensagem, a mensagem é colocada na fila para a caixa de correio. A ordem de enfileiramento está de acordo com a seqüência de tempo de envio da mensagem.

img)

3.3 Características do modelo de ator

O modelo Actor descreve um conjunto de axiomas para evitar a programação simultânea:

  • Todo o estado do ator é local e não pode ser acessado de fora.

  • Os atores devem se comunicar por meio da passagem de mensagens.

  • Um Ator pode responder a mensagens, sair de novos Atores, alterar o estado interno e enviar mensagens para um ou mais Atores.

  • Os atores podem se bloquear, mas os atores não devem bloquear seus threads em execução

A primeira linha imprime o caminho do HelloWorld Actor, que é o primeiro Actor criado no sistema. O caminho é: akka: // hello / user / helloworld. O primeiro hello representa o nome do sistema do ActorSystem, que é o primeiro parâmetro inserido durante a construção. usuário representa o usuário Ator, todos os usuários Atores serão montados no caminho do usuário. Finalmente, helloworld é o nome desse ator.

A segunda linha imprime o caminho do Ator Greeter, e a terceira e a quarta linhas são as informações geradas no Greeter.

A quinta linha indica que o sistema encontrou uma falha na entrega da mensagem, porque o HelloWorld parou sozinho, fazendo com que a mensagem enviada por Greeter não fosse entregue com sucesso.

Ao usar o Actor para desenvolvimento simultâneo, o foco não está mais no encadeamento.O agendamento do encadeamento foi encapsulado pela estrutura Akka e você só precisa se concentrar no objeto Actor. As informações são transmitidas entre os objetos Ator por meio do envio de mensagens exibidas.

Quando houver vários Atores no sistema, a Akka selecionará automaticamente os encadeamentos no pool de encadeamentos para executar nosso Ator. Diferentes atores podem ser executados pelo mesmo encadeamento ou um Ator pode ser executado por diferentes encadeamentos.

Nota: Não execute código demorado em um Ator, pois isso pode causar problemas de agendamento para outros Atores.

4 Por que os arquitetos Java precisam aprender a Akka?

Akka é escrito em linguagem Scala. Embora forneça uma interface de desenvolvimento Java, existem poucos desenvolvimentos baseados em Akka. No entanto, muitos frameworks distribuídos são feitos com akka, por exemplo, a comunicação distribuída do flink [3] depende do Akka.

Mas para equipes em nível de aplicativo, o desempenho sempre pode atender às necessidades e não há necessidade de perseguir limites de desempenho. Quanto mais confiável for o middleware, mais rápido será o desenvolvimento. Obviamente, as equipes de desenvolvimento de aplicativos preferem usar middleware distribuído, como Hadoop, spark, hive, flink, Kinesis, Kafka, Storm e outros componentes para resolver problemas.

Portanto, Akka não precisa aprender para o desenvolvimento de aplicativos. Mas para arquitetos, deve ser aprendido.

Pelo menos, vale a pena aprender os princípios de Akka.

5 exemplo introdutório Akka

O programa a seguir demonstra um exemplo simples de akka. Crie um Ator para processar um comando e interagir por meio da passagem de mensagens.

Apresente dependências:

    <dependency >
    <groupId> com.typesafe.akka</groupId >
    <artifactId>akka-actor_2.10</artifactId>
    <version>2.3.10</version>
    </dependency>
    <dependency >
        <groupId> com.typesafe.akka</groupId >
        <artifactId>akka-persistence-experimental_2.10</artifactId>
        <version>2.3.10</version>
    </dependency>

Criar objeto de comando

  //创建命令对象
    @Data
    @AllArgsConstructor
    static class Command implements Serializable
    {
        private static final long serialVersionUID = 1L;
        private String data;
    }

Criar objeto Ator

    //创建Actor对象
    static class SimpleActor extends UntypedActor
    {

        LoggingAdapter log = Logging.getLogger(getContext().system(), this);

        public SimpleActor()
        {
            log.info("SimpleActor constructor");
        }

        @Override
        public void onReceive(Object msg) throws Exception
        {

            log.info("Received Command: " + msg);
            if (msg instanceof Command)
            {
                final String data = ((Command) msg).getData();
                // emmit an event somewhere...

            } else if (msg.equals("echo"))
            {
                log.info("ECHO!");
            }
        }
    }

Iniciar ActorSystem

   public static void main(String[] args) throws InterruptedException
    {

        final ActorSystem actorSystem = ActorSystem.create("actor-system");

        Thread.sleep(5000);

        final ActorRef actorRef = actorSystem.actorOf(Props.create(SimpleActor.class), "simple-actor");

        actorRef.tell(new Command("CMD 1"), null);
        actorRef.tell(new Command("CMD 2"), null);
        actorRef.tell(new Command("CMD 3"), null);
        actorRef.tell(new Command("CMD 4"), null);
        actorRef.tell(new Command("CMD 5"), null);

        Thread.sleep(5000);

        log.debug("Actor System Shutdown Starting...");

        actorSystem.shutdown();

    }

Os resultados da execução principal são os seguintes:

[INFO] [11/01/2020 18:12:15.303] [actor-system-akka.actor.default-dispatcher-3] [akka://actor-system/user/simple-actor] SimpleActor constructor
[INFO] [11/01/2020 18:12:15.306] [actor-system-akka.actor.default-dispatcher-3] [akka://actor-system/user/simple-actor] Received Command: AkkaDemo.Command(data=CMD 1)
[INFO] [11/01/2020 18:12:15.306] [actor-system-akka.actor.default-dispatcher-3] [akka://actor-system/user/simple-actor] Received Command: AkkaDemo.Command(data=CMD 2)
[INFO] [11/01/2020 18:12:15.307] [actor-system-akka.actor.default-dispatcher-3] [akka://actor-system/user/simple-actor] Received Command: AkkaDemo.Command(data=CMD 3)
[INFO] [11/01/2020 18:12:15.307] [actor-system-akka.actor.default-dispatcher-3] [akka://actor-system/user/simple-actor] Received Command: AkkaDemo.Command(data=CMD 4)
[INFO] [11/01/2020 18:12:15.308] [actor-system-akka.actor.default-dispatcher-3] [akka://actor-system/user/simple-actor] Received Command: AkkaDemo.Command(data=CMD 5)

6 melhores práticas Akka

Cálculo do número primo

Requisitos: Use vários tópicos para encontrar o número de números primos dentro de 1.000.000

O fluxo de processamento do método de memória compartilhada é o seguinte:

img

O método tradicional usa bloqueio / sincronização para obter simultaneidade. Cada sincronização obtém o valor atual e permite que um thread determine se o valor é um número primo. Se for, o contador é incrementado em um de maneira sincronizada.

O fluxo de processamento do modelo de ator é o seguinte:

img

Usar o método do modelo de Ator dividirá esse processo em vários módulos, ou seja, dividido em vários Atores. Cada ator é responsável por diferentes partes e permite que vários atores trabalhem juntos por meio da passagem de mensagens.

Transferência bancária

img

Problema existente: quando o usuário A Actor está deduzindo dinheiro, o usuário B Actor não tem restrições. Neste momento, é legal operar o usuário B Actor. Neste caso, o modelo de ator puro é relativamente fraco e precisa ser adicionado. Mecanismo para garantir consistência.

Observação: o caso acima é usado apenas como referência para o modelo e não fornece uma implementação de referência. Para o código de implementação específico, você pode entrar na comunidade do Crazy Maker Circle para se comunicar

7 Estratégia de entrega de mensagens da Akka

Os aplicativos Akka são movidos por mensagens, e as mensagens são o componente central mais importante, além dos Atores. As mensagens passadas entre os atores devem satisfazer a imutabilidade, ou seja, o modo invariável, e as mensagens mutáveis ​​não podem ser usadas com eficiência em um ambiente simultâneo. Recomenda-se o uso de objetos imutáveis ​​em Akka. A declaração final do campo pode ser usada no código. Depois que a mensagem é construída, ela não pode ser alterada.

Estratégia de entrega de mensagens da Akka:

  • No máximo uma entrega: Cada mensagem nesta estratégia será entregue no máximo uma vez e pode haver falhas de entrega ocasionais, resultando em perda de mensagem. Essa estratégia é de alto desempenho.

  • Entrega pelo menos uma vez: Cada mensagem nesta estratégia será entregue pelo menos uma vez até ter sucesso. Em algumas situações ocasionais, o destinatário pode receber mensagens duplicadas, mas as mensagens não serão perdidas. Essa estratégia precisa salvar o status de entrega da mensagem e continuar tentando.

  • Entrega precisa: todas as mensagens têm a garantia de serem entregues com precisão e recebidas uma vez com sucesso, e não serão perdidas nem repetidas. Essa estratégia é a mais cara e difícil de implementar.

Quanto à confiabilidade da mensagem: não há necessidade de garantir a confiabilidade da mensagem na camada Akka, é muito caro e desnecessário. A confiabilidade da mensagem deve ser garantida na camada de negócios do aplicativo e, às vezes, a perda de algumas mensagens está de acordo com os requisitos do aplicativo.

A ordem de entrega da mensagem: Akka pode garantir a ordem de entrega até certo ponto. Se o ator A1 enviar três mensagens M1, M2 e M3 para A2 em sequência e o ator A3 enviar três mensagens M4, M5 e M6 para A2 em sequência, o sistema pode garantir:

  • Se M1 não for perdido, deve ser recebido por A2 antes de M2 ​​e M3.

  • Se M2 não for perdido, deve ser recebido por A2 antes de M3.

  • Se M4 não for perdido, deve ser recebido por A2 antes de M5 e M6.

  • Se M5 não for perdido, deve ser recebido por A2 antes de M6.

  • Para A2, as mensagens de A1 a A3 não são garantidas como sequenciais.

img

Além disso, essa regra de entrega de mensagem não é transferível, conforme mostrado na figura abaixo:

img

A ordem em que C recebe M1 e M2 não é garantida


Voltar para ◀ Crazy Maker Circle

Comunidade de pesquisa de alta concorrência do Crazy Maker Circle-Java, abre as portas para grandes fábricas para todos

Acho que você gosta

Origin blog.csdn.net/crazymakercircle/article/details/109432688
Recomendado
Clasificación