[Esta postagem também aparece no blog do Dustin no github].
Criamos algumas novas operações de protocolo para as pessoas que estão criando aplicativos. O objetivo geral de adicionar uma operação é mantê-la ortogonal a outros comandos e, ao mesmo tempo, aprimorar a funcionalidade de modo a permitir que você faça coisas que não podiam ser feitas antes ou que, pelo menos, eram comuns e difíceis de fazer com eficiência.
Aqui está uma descrição dos novos comandos e uma ideia de como eles podem ser usados.

Sincronização
O outro novo conceito que introduzimos é um sincronização comando para fornecer uma barreira em que você espera que os dados de um aplicativo mudem de estado de maneiras específicas, como a mudança de um item de um valor conhecido ou a obtenção de um nível específico de durabilidade.
Um breve histórico sobre como isso funciona no membase (para o qual implementamos sincronização para começar): O mecanismo do Membase tem o que é efetivamente um espaço aéreo entre a interface de rede e o disco. As operações são quase todas processadas de e para a RAM e, em seguida, replicadas e mantidas de forma assíncrona. Os itens recebidos estão disponíveis para solicitação imediatamente após o retorno do seu comando de mutação (ou seja, a próxima solicitação de uma determinada chave retornará o item que acabou de ser definido), mas a replicação e a persistência ocorrerão em breve.
A base de membrana sincronização é um pouco análogo ao comando fsync ou talvez msync no sentido de que você pode primeiro fazer o lobby de itens livremente na membase e verificar se ela os aceitou no nível mais baixo de disponibilidade. Quando você tiver armazenado um conjunto de itens críticos, poderá emitir um sincronização com o conjunto de suas chaves críticas e o nível de durabilidade exigido, e o servidor bloqueará até que esse nível seja atingido (ou aconteça algo que nos impeça de fazer isso).
Houve discussões sobre diferentes semânticas (como um modo totalmente sincronizado ou um modo específico de set+sync tipo de comando). Embora um único set+sync seria uma viagem de ida e volta a menos do que fazer um comando separado definir e sincronizaçãoNa prática, isso faz pouca diferença, pois o efeito típico de um sincronização é um atraso. Isso, no entanto, tem o custo de dificultar muito a realização de qualquer tipo de lote ou pipelining prático. É possível sincronizar após cada comando, após um lote grande ou em itens selecionados de um lote grande.
Em que você pode sincronizar?
A especificação permite que um determinado conjunto de chaves seja monitorado para uma das seguintes alterações de estado:
- Aguardar a replicação
- Aguarde a persistência
- Aguardar a replicação e Persistência
- Aguardar a replicação ou Persistência
- Aguardar a mutação
Também há espaço para um sinalizador "qualquer vs. todos" para as chaves, no qual você pode entregar ao servidor um conjunto de chaves e ser informado assim que qualquer uma delas mudar para o estado desejado, em vez de esperar por todas elas.
Exemplo
Dado um saco gigante de itens, com uma mistura de itens importantes (quero armazenar) e itens realmente importantes (preciso garantir que sejam armazenados antes de devolver), vamos fazer a coisa certa.
"""Armazene uma coleção de itens.
Os itens serão armazenados de forma assíncrona e, em seguida, os itens importantes
será sincronizado antes de retornar."""
importante = []
para i em itens:
mc.definir(i.chave, i.exp, i.bandeiras, i.valor)
se i.importante:
importante.anexar(i)
mc.sync_replication_or_persistence(importante)
(observe que um cliente python suporta esses recursos, mas não exatamente com essa API, mas isso deve lhe dar a ideia básica)
Da mesma forma, é possível limitar a taxa de inserções de modo que os itens não sejam inseridos mais rapidamente do que podem ser gravados no disco.
"""Armazene uma coleção de itens sem construir uma grande
carteira de replicações."""
para n, i em enumerar(itens, 1):
mc.definir(i.chave, i.exp, i.bandeiras, i.valor)
se (n % sync_every) == 0:
mc.sync_replication(i)
Cada sync_every (padrão 1000) aguarda que a sincronização seja recuperada. Configuração sync_every para um faria com que sincronizássemos totalmente cada item.
Toque
Alguns proprietários de projetos nos disseram que gostariam de poder ter itens com uma janela deslizante de expiração. Por exemplo, em vez de um item expirar após cinco minutos de mutação (que é como você especifica o tempo de vida de um objeto hoje), gostaríamos que ele expirasse após cinco minutos de inatividade.
Se você estiver familiarizado com caches LRU (como o memcached), deve observar que isso é semanticamente muito diferente do LRU. Com um LRU, efetivamente não nos importamos com dados antigos. Os casos de uso para toque exigem que desativemos ativamente o acesso a dados inativos em uma programação definida pelo usuário.
O toque pode ser usado para ajustar a expiração em uma chave existente sem tocar no valor. Ele usa o mesmo tipo de definição de expiração que todos os comandos de mutação usam, mas não toca de fato nos dados.
Semelhante a toque adicionamos um fusca (obter e tocar) que retorna os dados e ajusta a expiração ao mesmo tempo. Para a maioria dos casos de uso, fusca é provavelmente mais apropriado do que toquemas isso realmente depende de como você cria seu aplicativo.
Exemplo de uso
Uso de toque e fusca são bastante simples. Um padrão muito comum pode ser o armazenamento de dados de sessão em que queremos que os dados "ociosos" sejam removidos rapidamente, mas que os dados ativos permaneçam enquanto estiverem ativos.
"""Obtenha um objeto de sessão válido para o ID de sessão fornecido.
As sessões durarão apenas cinco minutos.
Unauthenticated será lançado se a sessão
não pode ser carregado."""
s = mc.fusca(session_id, max_session_age)
se não s:
lançar Não autenticado()
retorno s
Este exemplo mostrou um carregador de sessão simples que mantém a sessão ativa e sinaliza as sessões de missão para outra parte da pilha de aplicativos que pode lidar com logins e outras coisas.
Disponibilidade
Estamos usando esse material, mas ainda não alcançamos a disponibilidade universal.
Servidores
Membase 1.7 fornece esse toque e fusca funcionalidade e parcial sincronização funcionalidade.
Para sincronizaçãoNo entanto, o protocolo permite o rastreamento de até 16 réplicas, mas o membase como um cluster usa replicação transitiva, portanto não é possível rastrear quando a segunda réplica está completa a partir do host principal (muito menos a décima sexta). O protocolo permite o rastreamento de até 16 réplicas, mas o membase como um cluster usa replicação transitiva, portanto, não é possível rastrear quando a segunda réplica está completa a partir do host principal (muito menos a décima sexta!).
Da mesma forma, escrevemos a maior parte do código para sincronização na persistência, mas antes de nossas estratégias de armazenamento 2.0, achamos que isso poderia ser mais prejudicial do que útil na maioria dos aplicativos. Mesmo com nossas estratégias 2.0, é provável que não seja tão apropriado quanto o rastreamento de replicação para todos os dados, exceto os absolutamente mais importantes.
O Memcached 1.6(ish) tem suporte para toque e fusca no mecanismo padrão (que também é fornecido no Membase).
Clientes
Além de mc_bin_client.py (que é uma espécie de cliente de referência/jogo que vem com o membase e com o qual escrevemos muitas das ferramentas), ainda temos suporte em dois clientes, mas estamos considerando o recurso "em evolução", pois estamos tentando encontrar a melhor maneira de fazer isso. O feedback é muito mais do que bem-vindo!
Java
O spymemcached 2.7 tem suporte para toque, fuscae sincronização.
C Sharp
O cliente C# da enyim para memcached tem suporte para toque, fuscae sincronização em um lançamento que deve chegar às prateleiras em breve.
Fantástico! Analisarei o novo código e darei minha opinião, conforme solicitado - obrigado por todo o trabalho árduo!
No entanto, acreditamos que ele pode ser mais prejudicial do que útil na maioria dos aplicativos. Mesmo com nossas estratégias 2.0,