Sunday 26 November 2017

Infinispan Cache Putforexternalread


Eu estou usando Infinispan como um cache L2 hibernate. Em um sistema de carga normal em execução sem um problema. Mas quando a carga colocada no sistema a seguinte exceção foi lançada do cluster de cache. Mesmo que isso não causar um impacto funcional relatando um ERRO parece um problema. Infinispan versão. 5.3 Mais informações sobre o teste. Este cluster de cache L2 hibernate tinha quatro nós. Durante o teste eu não atualizei o cache (Entidades no cache didnt update). Entre quatro nodos, dois nodos utilizaram muito o cache. Mas principalmente eu vi esse erro em outros dois nós. Configuração do cache Hibernate L2 Agradeça sua ajuda. Eu atualizei o bug com mais informações. Eu posso ver o erro estava relatando continuamente. Eu não estava atualizando nenhuma entidade em cache durante o teste. Assim que não razão para chamar putForExternalRead () várias vezes. Também não consigo ver uma evidência para chamar putForExternalRead () do log. Eu posso ver visitPutKeyValueCommand () no log. Eu didn39t encontrar qualquer recurso para confirmar Hibernate L2 cache use putForExternalRead () para inserções de cache em vez de put (). Tenho medo de engolir a exceção sem ter uma imagem clara. Ndash era Mar 4 15 at 19:14 Como doc diz, a entidade é gravada no cache após it39s ler do banco de dados. Quando duas leituras simultâneas não conseguem encontrar a entidade no cache L2, elas a recuperam do banco de dados e a gravam no cache dessa maneira - e uma delas falha porque vê que a entrada já está escrita. A evidência é PUTFOREXTERNALREAD sinalizador no comando. Ndash Flavius ​​Mar 5 15 at 11: 31O que é Infinispan Infinispan é um armazenamento de dados de chave / valor em memória em memória com esquema opcional, disponível sob a Licença de Apache 2.0. Ele pode ser usado como uma biblioteca embutida Java e como um serviço independente de linguagem acessado remotamente sobre uma variedade de protocolos (HotRod, REST, Memcached e WebSockets). Ele oferece funcionalidades avançadas, como transações, eventos, consultas e processamento distribuído. Leia mais sobre nossos recursos Armazene e recupere Escalar e Compartilhar Replicar dados para todos os nós Distribuir dados para aumentar a capacidade Acesse seus dados remotamente Escreva seus aplicativos em C Escreva suas aplicações em C Escreva suas aplicações em Javascript Ouça e pesquise Detecte quando os dados mudam em um cache embutido Detectar quando os dados mudam em um cache remoto Índice e pesquisar seus dados Calcular fluxos distribuídos Executar operações complexas com scripts Integrar com o Apache SparkInfinispan Hibernate Melhorias do cache de segundo nível TRABALHO EM ANDAMENTO. TODO: adiciona sobre a capacidade de incorporar configurações de cache diretamente nas propriedades do Hibernate. XML snippets Este wiki contém idéias para aprimoramento na implementação do cache de segundo nível do Hibernate baseada em Infinispan que aborda melhorias de desempenho e falta de funcionalidade. Issues. jboss. org/browse/ISPN-5720 putForExternalRead não pode adquirir bloqueio no modo de invalidação Local vs Clustered A implementação atual fornece uma implementação de fábrica de região única, InfinispanRegionFactory. Independentemente do Hibernate estar em cluster ou não. Para poder abordar a melhoria do desempenho em diferentes cenários, ajudaria a separar a região em duas regiões, uma vez para local, único nó, cenários e outro para ambientes cluster multi-nó. Fazendo isso, cada região poderia tirar o máximo de cada caso de uso, p. Aplique bandeiras de contexto relevantes para o caso de uso. Evite putForExternalRead iniciando uma nova transação ao usar caches locais e entidades somente leitura. Estratégias simultâneas ausentes Atualmente, a implementação de 2LC baseada em Infinispan suporta somente estratégias de simultaneidade de leitura e transacionais e, portanto, não são implementadas nem leitura-estrita nem leitura-escrita-não-rígida. Essas duas estratégias são usadas quando nenhum gerenciador de transações JTA está disponível e as entidades / coleções precisam ser atualizadas. Implementar essas estratégias de simultaneidade para caches locais é relativamente simples. No entanto, para ambientes em cluster, você deseja evitar aplicar parcialmente atualizações ao redor do cluster e usar um gerenciador de transações evita isso. Uma vez que a maneira rápida de contornar esse problema seria configurar o cache de entidade / coleção com um gerenciador de transações em lote. UPDATE. Estratégia de leitura e escrita foi implementada. Na verdade, a opção de leitura-escrita transacional não importa, a maneira apropriada é selecionada de acordo com a configuração de cache Infinispan. Além disso, quando a entidade é marcada como imutável, o modo de somente leitura é usado, embora ele não mude muito (alguma sincronização é evento obrigatório para entidades somente leitura para impedir o staleness após a remoção). FAÇAM . Eu não acho que a incorporação de XML em propriedades (como um TODO acima sugere) é a melhor maneira. Eu prefiro considerar a remoção da configuração XML do ORM alltogether e configurar o cache programmaticaly com base na estratégia, e para outras opções (como o modo de invalidação / replicação) mantê-los em propriedades. Realmente precisamos expor os tempos limite de bloqueio, o modo de sincronização, etc. O problema de manter o 2LC consistente (isto é, não fornecer dados obsoletos após a transação do BD ter sido comprometida) pode ser resumido em Não fornecer dados que estão prestes a ser atualizados. Isso requer que cada gravação em DB seja envolvida - antes que o banco de dados seja comprometido, devemos invalidar os dados antigos (para que não os apresentemos depois que o banco de dados está comprometido) e desativar quaisquer tentativas de cache Para reativar o cache novamente. A definição de leitura obsoleta precisa de algum esclarecimento: a leitura pode ser considerada obsoleta quando acontece depois que o DB é cometido (você pode descobrir lendo uma entrada não armazenada em cache do DB que foi cometida na mesma transação) ou após a confirmação Thread termina o commit (isso significa que depois que todas as sincronizações terminarem). Quando o cache está no modo de invalidação (as estratégias baseadas em PutFromLoadValidator), todas as invalidações acontecem antes do DB ser comprometido, aderindo a um sentido mais estrito. Nos modos distribuídos / replicados (políticas baseadas em tombstones), relaxamos um pouco: enquanto as remoções são executadas antes do commit do DB, as atualizações mantêm o valor e o alteram apenas a partir das sincronizações afterCompletion. Essa decisão pode ser revista ainda. Essas correções incorrem em algum overhead de desempenho em comparação com a implementação anterior - precisamos de dois RPCs para cada modificação (o desempenho de leitura não mudou). O segundo RPC no modo de invalidação e para o modo de remoção dist / repl é assíncrono (inserções e atualizações no modo de invalidação são ainda seguidas por PFER), inserções / atualizações de dist / repl precisam do RPC síncrono, uma vez que estas sobrescrevem o valor antigo. Esta implementação foi compilada em cima do código PutFromLoadValidator existente ea ideia de como a operação putFromLoad é verificada em relação ao registro armazenado no cache local de puts pendente (PP) persiste. Uma vez que após as mudanças de API para 5.0 podemos usar IDs de entidade como chaves diretamente (sem envolvê-las junto com informações de tipo de origem), cada cache de entidade / coleção agora tem seu próprio cache de PP. No passado, a entrada em PP continha apenas os registros do thread thats prestes a executar a operação putFromLoad, agora ele também contém registros para cada invalidator. Cada registro é timestamped para que qualquer registro vazado pode eventualmente expirar. Para implementar as duas fases acima mencionadas, temos de injetar interceptores personalizados que reagem na transação sendo comprometida, para caches não-transacionais nós registramos uma sincronização. Isso pode ser otimizado ainda mais se houver várias sincronizações para uma transação. O código original não invalidava nada quando a entrada foi atualizada / inserida. Como isso pode interagir com remoções simultâneas, temos que invalidar o em cada operação. A única exceção é evict (), pois isso não modifica o conteúdo do DB, portanto, podemos apenas remover a entrada do cache. Como esperamos que a entidade será armazenada em cache após update / insert, agendaremos uma operação PFER se a transação for bem-sucedida. A invalidação completa da região é baseada em timestamps: durante a remoção de entidades, nada pode ser armazenado em cache, e após a invalidação terminar, somente as leituras nas transações iniciadas após a invalidação terem sido concluídas (a remoção em todos os nós foi executada) pode ser colocada em cache novamente. Caches de modo replicado / distribuído: Tombstones A necessidade de manter o cache separado para puts pendentes nos levou a uma idéia de usar entradas expiraveis, chamadas lápides para marcar a remoção de entidades do cache. Inicialmente eu pensei que escrever uma entidade singleton para o cache em vez de remoção iria corrigir o problema. Seria realmente desativar todas as atualizações de cache, mas há uma falha: ele iria desativá-los até expiração de lápide, que geralmente é inaceitavelmente longo tempo. Portanto, as lápides são inseridas antes do commit do banco de dados e invalidadas após o commit do banco de dados. Se houver duas remoções simultâneas, temos que rastrear ambas na tombstone e permitir a atualização de cache nesta entrada somente após todas as remoções terem terminado1. Para executar estes mesclar (e outras operações), nós usamos TombstoneCallInterceptor que simula o comportamento de PutKeyValueCommand com algum valor adicionado. Nós não usamos PFERs para atualizar o cache, mas colocar um TombstoneUpdate especial com todas as bandeiras como PFER, mas sem o PFER flag (desde Infinispan não iria ler uma entrada existente no contexto de chamada de comandos se este tivesse o PFER flag). TombstoneUpdate carrega o novo valor eo carimbo de data / hora do início da transação - as atualizações com carimbos de data / hora mais baixos do que o último timestamp do Tombstone (a última remoção concluída) são descartadas. Continua. 1DB deve proibir dois remoções bem-sucedidas ao mesmo tempo. Ou não OUTDATED. Na configuração atual, os caches transacionais do Infinispan são necessários ao executar o Hibernate 2LC em um cluster ou ao usar o Hibernate localmente com entidades que precisam ser atualizadas. Grandes melhorias de desempenho poderiam ser alcançadas se nenhuma transação seria necessária para manter o cache consistente. Para que uma implementação totalmente não-transacional funcione, os seguintes casos de uso precisarão ser tratados: Evite atualizações / inserções substituindo exclusões Sem transações, as lápides são necessárias para saber que uma entrada em cache foi excluída. Se as lápides forem implementadas, os metadados precisam ser deixados ao redor para que, se uma atualização / inserção vier, podemos detectar se eles devem ser aplicados se forem mais recentes, ou não devem ser aplicados se forem anteriores à exclusão propriamente dita. UPDATE. Mesmo que conheçamos a versão, não é uma garantia de que a transação de banco de dados será bem-sucedida, para que possamos inserir a entidade somente após a transação ser bem-sucedida. Precisamos2 para parar PFERs antes do commit de banco de dados, então a versão precisa ser escrita (sincronamente em cluster) antes disso. Isso nos deixa assim: antes do commit do banco de dados, tornar as versões real e inferior inválidas se o TX for bem sucedido, podemos atualizar (assíncrona) o valor (se não houver nenhuma outra modificação entretanto) se o TX falhar, devemos reverter a invalidação If we Não atualizar o valor após tx, weve reduziu a quantidade de RPCs necessários para 1 (em caso de sucesso), mas que um RPC armazenado será executado por um PFER mais tarde, como havent cache o valor no primeiro RPC. 2 Precisamos interrompê-los se quisermos que as leituras atualizadas até mesmo antes que a transação modificadora termine totalmente. Se relaxarmos essa demanda, poderíamos apenas atualizar o valor após a transação (com uma verificação de versão para evitar sobrescrever valor mais recente) e deixar putFromLoads fazer o mesmo. Observe que os testes de consistência atuais não detectariam isso. Evitar actualizações mais antigas substituindo actualizações mais recentes Uma vez que as transacções estão desactivadas, as informações de versão fornecidas pela própria entidade / colecção (frequentemente ditadas pelo DB) podem indicar qual versão da entidade / colecção é mais recente do que a outra e evitar este problema. Evite atualizações parciais do cluster Quando estiver sendo executado em um cluster, há uma possibilidade de que uma atualização não possa ser aplicada em todos os nós. Quando isso acontece e as transações são ativadas, há uma fase de reversão que garante que tal coisa não aconteça. Com transações desativadas, não há nenhuma fase de reversão. Se o cache é síncrono, o chamador obteria uma falha, mas itd sua responsabilidade de repetir a atualização ou remover a entidade / coleção do cache cluster de largura, que poderia ser novamente parcialmente aplicada. Se o cache fosse assíncrono, a falha passaria despercebida. Portanto, a questão seria: como um nó detectaria que, quando uma entidade / coleção é recuperada do cache, o seu stale porque o banco de dados contém uma versão mais nova? O cache está lá para evitar ter que ir ao banco de dados. UPDATE. Observe que os caches assíncronos não foram considerados nas correções de consistência abaixo. Qualquer assincronicidade precisa ser explicitamente solicitada no algoritmo. Se a falha ocorrer na primeira fase, reverteremos toda a transação e agiremos de acordo com as outras entradas. Como durante a atualização o cache é geralmente em estado de invalidação (não fornecendo qualquer valor) uma atualização parcial quebrado na segunda fase apenas faz com que a entrada seja não-cacheable até a invalidação expirar. Uma das áreas mais complexas dentro da implementação atual do Hibernate 2LC baseada em Infinispan é o validador putFromLoad que foi adicionado para resolver o HHH-4520. Efetivamente, ele valida se a entidade / coleção que foi lida do banco de dados pode ser permitida para ser colocada no cache, uma operação vulgarmente conhecida como putFromLoad. Para acelerar as operações de putFromLoad, o Infinispan usa uma operação putForExternalRead que acelera as chamadas colocadas ao colocar dados provenientes de uma fonte externa. Um aspecto importante desta operação é que ele não participa de uma transação em andamento, portanto, pode haver situações em que putForExternalRead poderia armazenar dados obsoletos no 2LC. Exemplo: Transação 1 (T1) lê coleção, resultados em falta de cache. T1 vai para o banco de dados para ler coleção Transação 2 (T2) lê coleção, falta de cache, resultados em falta de cache. T2 vai para banco de dados para ler coleção T2 chamadas Infinispans putForExternalRead para armazenar a coleção T2 remove ou atualiza coleção T1 faz Infinispan putForExternalRead para armazenar coleção obsoleta A maneira Infinispan 2LC implementação fica em torno disso, enquanto ainda usando putForExternalRead é fazendo o seguinte: Quando Hibernate lê Do cache ea entidade / coleção não estiver lá, uma pendente put é registrada na chave validator entity / collection. Depois de ler os dados do banco de dados, ele tenta adquirir um bloqueio nessa chave. Se o bloqueio é adquirido, é permitido colocar os dados no 2LC. Se o bloqueio não é adquirido, os dados não podem ser colocados no cache. Se houver atualizações para a entidade / coleção no tempo médio, anteriormente pendentes pendentes são invalidados, e como resultado disso, a aquisição do bloqueio falha. Essas opções pendentes são armazenadas em um cache Infinispan local com configurações de expiração agressivas, de forma que as puts pendentes são removidas caso haja algum problema depois de registrá-las. O cenário acima não pode acontecer quando as transações estão localizadas em nós diferentes ao usar a configuração padrão Infinispan 2LC que configura caches de entidade / coleção com invalidação. Com a invalidação, as operações putForExternalRead não são enviadas ao redor do cluster, pois não há nada a invalidar. Os dados putForExternalRead coloca no cache é dados que vem do banco de dados. Como resultado disto, não há tal risco de armazenar dados obsoletos em outro nó remotamente. No entanto, se a cache 2LC entidade / coleção foi configurada para usar replicação ou distribuição, uma vez que putForExternalRead replicar assincronamente nesses set ups, o risco estaria lá. Não seria necessário ter este colocar a partir do validador de carga se Infinispans colocar foi usado em vez de putForExternalRead. Mas para a grande maioria dos casos, putForExternalRead oferece um desempenho muito melhor especialmente para situações em que os dados são simplesmente carregados a partir do banco de dados e não atualizados nem removidos. Lembre-se de que o put do validador de carga é necessário também para entidades somente leitura / coleções porque elas podem ser inseridas e excluídas e as exclusões podem gerar o problema explicado acima. Em testes de desempenho anteriores, esta área parecia ser um hotspot de desempenho e tem sido desde tweaked para um melhor desempenho. A questão aqui é se há uma maneira melhor de contornar esta questão de leitura obsoleto, mantendo um bom desempenho. Tombstones e comparação baseada em informações de versão fornecidas pelo Hibernate evitariam uma leitura obsoleta substituindo uma exclusão (tombstone) ou uma leitura obsoleta substituindo uma versão mais recente (versionamento). Remote Infinispan 2LC Até agora, o Hibernate conversou com a Infinispan usando o modo embutido, onde a Infinispan mantém os dados armazenados em cache na mesma JVM onde o Hibernate está sendo executado. No entanto, há um tempo, tem havido uma maneira alternativa de interagir com caches Infinispan usando APIs remotas que permitem que os dados sejam armazenados em um único servidor do servidor Infinispan ou cluster deles. Pode haver situações em que o acesso a Infinispan 2LC remotamente poderia ser mais adequado que o atual modo incorporado, por exemplo: Quando os dados são muito grandes, muito maiores do que a capacidade da JVM onde o Hibernate está em execução e os dados são intensivos de leitura, com um Infinispan separado Servidor cluster como 2LC seria muito útil, diminuindo a quantidade de carga no banco de dados. Para escrever entidades pesadas em um conjunto em cluster, ter que enviar mensagens de invalidação SYNC ao redor do cluster pode ser mais caro do que simplesmente falar com uma única instância do servidor Infinispan que mantém o cache na memória. Quando você deseja executar a camada de aplicativo onde o Hibernate está localizado em vários nós que não estão agrupados. Nesse caso, você não pode ter várias instâncias de cache de nível local executando porque eles não serão capazes de invalidar um ao outro, por exemplo, quando os dados no cache de segundo nível é atualizado. Neste caso, ter um cache de segundo nível remoto poderia ser uma saída para se certificar de que seu cache de segundo nível está sempre em um estado consistente, todos os nós na camada de aplicativo apontando para ele. Em vez de ter o cache de segundo nível em um servidor remoto, você deseja simplesmente manter o cache em uma VM separada dentro da mesma máquina. Neste caso, você ainda teria a sobrecarga adicional de falar através de outra JVM, mas não teria a latência de uma rede. O benefício de fazer isso é: Tamanho do cache separado do aplicativo, uma vez que o cache eo servidor de aplicativos têm perfis de memória muito diferentes. Um tem muitos objetos de curta duração, eo outro poderia ter muitos objetos de longa duração. Para fixar o cache eo servidor de aplicativos em diferentes núcleos de CPU (usando numactl), e até mesmo pin-los a diferentes fisicamente memória baseada nos nós NUMA. Até recentemente, a implementação de uma versão remota do Infinispan 2LC não tinha sido considerada porque o Infinispans Remote Caches estava faltando perto do cache. Sem ele, cada operação de leitura Infinispan precisaria ser enviada para o (s) servidor (es) Infinispan, adicionando latência considerável até mesmo a mais simples das verificações de cache. No entanto, o Cache Remoto Infinispans recentemente adicionou o Cache Próximo para que os clientes possam manter pequenas caches locais do lado do cliente, com políticas de despejo agressivas, que aceleram o acesso remoto de dados, evitando dados obsoletos, reagindo aos eventos provenientes do servidor Infinispan. Esta melhoria significativa torna uma implementação remota Infinispan 2LC uma solução viável. NOTA . O cache próximo é projetado para ser atualizado assincronamente após a atualização ocorre no servidor. Isso torna as opções um pouco limitadas - não podemos garantir leituras não viciadas. Por conseguinte, penso que quando se utiliza o cache próximo podemos suportar apenas o modo nonstrict-read-write (que não dá quaisquer garantias).

No comments:

Post a Comment