{"id":98090,"date":"2020-10-24T02:42:38","date_gmt":"2020-10-24T00:42:38","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux"},"modified":"2020-11-18T00:58:48","modified_gmt":"2020-11-17T22:58:48","slug":"ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux","title":{"rendered":"Armazenamento de dados sustent\u00e1vel e APIs de arquivos Linux","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Eu, ao investigar a sustentabilidade do armazenamento de dados em sistemas de nuvem, decidi me testar e me certificar de que compreendo os conceitos b\u00e1sicos. Eu <noindex><a rel=\"nofollow\" href=\"https:\/\/www.evanjones.ca\/durability-nvme.html\">comecei lendo a especifica\u00e7\u00e3o NVMe<\/a><\/noindex> para entender quais garantias sobre o armazenamento de dados sustent\u00e1vel (ou seja, garantias de que os dados estar\u00e3o acess\u00edveis ap\u00f3s uma falha no sistema) s\u00e3o oferecidas pelos discos NVMe. Eu cheguei \u00e0s seguintes conclus\u00f5es principais: os dados devem ser considerados corrompidos a partir do momento em que um comando para grava\u00e7\u00e3o de dados \u00e9 emitido, at\u00e9 o momento em que a grava\u00e7\u00e3o \u00e9 conclu\u00edda no meio de armazenamento. No entanto, na maioria dos programas de grava\u00e7\u00e3o de dados, chamadas de sistema s\u00e3o utilizadas sem grandes preocupa\u00e7\u00f5es.<\/p>\n<p>Neste material, eu investigarei os mecanismos de armazenamento de dados sustent\u00e1vel fornecidos pelas APIs de arquivos Linux. Parece que tudo deve ser simples: o programa chama o comando <code>write()<\/code>, e ap\u00f3s a conclus\u00e3o deste comando, os dados devem estar seguros no disco. Mas <code>write()<\/code> apenas copia os dados do aplicativo para o cache do n\u00facleo, que est\u00e1 localizado na mem\u00f3ria RAM. Para for\u00e7ar o sistema a gravar os dados no disco, \u00e9 necess\u00e1rio usar alguns mecanismos adicionais.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/524172\/\"><img decoding=\"async\" alt=\"Armazenamento de dados sustent\u00e1vel e APIs de arquivos Linux\" src=\"\/wp-content\/uploads\/2020\/10\/b974dcb9fc546cae03ade4f3d8f5dc25.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p>De modo geral, este material \u00e9 um conjunto de notas sobre o que aprendi sobre o assunto que me interessa. Se eu resumir brevemente o mais importante, seria que para organizar o armazenamento de dados sustent\u00e1vel, deve-se usar o comando <code>fdatasync()<\/code> ou abrir arquivos com a flag <code>O_DSYNC<\/code>. Se voc\u00ea estiver interessado em detalhes sobre o que acontece com os dados ao serem transferidos do c\u00f3digo do programa para o disco, d\u00ea uma olhada em <noindex><a rel=\"nofollow\" href=\"https:\/\/lwn.net\/Articles\/457667\/\">este<\/a><\/noindex> artigo.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Caracter\u00edsticas do uso da fun\u00e7\u00e3o write()<\/h2>\n<p>\nA chamada de sistema <code>write()<\/code> \u00e9 definida no padr\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/POSIX\">IEEE POSIX<\/a><\/noindex> como uma tentativa de gravar dados em um descritor de arquivo. Ap\u00f3s a conclus\u00e3o bem-sucedida da execu\u00e7\u00e3o, <code>write()<\/code> as opera\u00e7\u00f5es de leitura de dados devem retornar exatamente aqueles bytes que foram previamente gravados, fazendo isso mesmo quando os dados s\u00e3o acessados por outros processos ou threads (<noindex><a rel=\"nofollow\" href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/functions\/write.html#tag_16_685_08\">aqui<\/a><\/noindex> se\u00e7\u00e3o correspondente do padr\u00e3o POSIX). <noindex><a rel=\"nofollow\" href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/functions\/V2_chap02.html#tag_15_09_07\">Aqui<\/a><\/noindex>, na se\u00e7\u00e3o dedicada \u00e0 intera\u00e7\u00e3o de fluxos com opera\u00e7\u00f5es de arquivos comuns, h\u00e1 uma observa\u00e7\u00e3o que diz que se cada um dos dois fluxos invocar essas fun\u00e7\u00f5es, cada chamada deve perceber ou todas as consequ\u00eancias designadas resultantes da execu\u00e7\u00e3o da outra chamada, ou n\u00e3o perceber nenhuma consequ\u00eancia. Isso leva \u00e0 conclus\u00e3o de que todas as opera\u00e7\u00f5es de entrada\/sa\u00edda de arquivos devem manter o bloqueio do recurso com o qual est\u00e3o trabalhando.<\/p>\n<p>Isso significa que a opera\u00e7\u00e3o <code>write()<\/code> \u00e9 at\u00f4mica? Do ponto de vista t\u00e9cnico \u2014 sim. As opera\u00e7\u00f5es de leitura de dados devem retornar tudo ou nada do que foi gravado com <code>write()<\/code>. Mas a opera\u00e7\u00e3o <code>write()<\/code>, de acordo com o padr\u00e3o, n\u00e3o precisa necessariamente completar gravando tudo o que foi solicitado a gravar. \u00c9 permitido que ela escreva apenas uma parte dos dados. Por exemplo, podemos ter dois fluxos, cada um anexando 1024 bytes a um arquivo, descrito pelo mesmo descritor de arquivo. Do ponto de vista do padr\u00e3o, \u00e9 aceit\u00e1vel um resultado em que cada uma das opera\u00e7\u00f5es de grava\u00e7\u00e3o consiga anexar apenas um byte ao arquivo. Essas opera\u00e7\u00f5es permanecer\u00e3o at\u00f4micas, mas, ap\u00f3s sua conclus\u00e3o, os dados gravados no arquivo estar\u00e3o embaralhados. <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/a\/42442926\/413438\">Aqui<\/a><\/noindex> uma discuss\u00e3o muito interessante sobre esse assunto no Stack Overflow.<\/p>\n<h2>As fun\u00e7\u00f5es fsync() e fdatasync()<\/h2>\n<p>\nA maneira mais simples de gravar dados no disco \u00e9 chamando a fun\u00e7\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/man7.org\/linux\/man-pages\/man2\/fsync.2.html\">fsync()<\/a><\/noindex>. Essa fun\u00e7\u00e3o solicita ao sistema operacional a transfer\u00eancia de todos os blocos modificados do cache para o disco. Isso inclui todos os metadados do arquivo (hora de acesso, hora de modifica\u00e7\u00e3o do arquivo, e assim por diante). Acredito que a necessidade desses metadados surge raramente, portanto, se voc\u00ea souber que eles n\u00e3o s\u00e3o importantes para voc\u00ea, pode usar a fun\u00e7\u00e3o <code>fdatasync()<\/code>. No <noindex><a rel=\"nofollow\" href=\"https:\/\/man7.org\/linux\/man-pages\/man2\/fdatasync.2.html\">ajuda<\/a><\/noindex> para <code>fdatasync()<\/code> diz que, ao executar essa fun\u00e7\u00e3o, \u00e9 realizado o salvamento no disco de uma quantidade de metadados que \u00e9 'necess\u00e1ria para a execu\u00e7\u00e3o correta das pr\u00f3ximas opera\u00e7\u00f5es de leitura de dados'. E isso \u00e9 exatamente o que preocupa a maioria dos aplicativos.<\/p>\n<p>Um dos problemas que pode surgir aqui \u00e9 que esses mecanismos n\u00e3o garantem que o arquivo possa ser recuperado ap\u00f3s uma poss\u00edvel falha. Em particular, ao criar um novo arquivo, \u00e9 necess\u00e1rio chamar <code>fsync()<\/code> para o diret\u00f3rio que o cont\u00e9m. Caso contr\u00e1rio, ap\u00f3s uma falha, pode acontecer que esse arquivo n\u00e3o exista. A raz\u00e3o para isso \u00e9 que, no UNIX, devido ao uso de links r\u00edgidos, o arquivo pode existir em v\u00e1rios diret\u00f3rios. Portanto, ao chamar <code>fsync()<\/code> n\u00e3o h\u00e1 como o arquivo saber quais diret\u00f3rios tamb\u00e9m devem ser gravados no disco (<noindex><a rel=\"nofollow\" href=\"https:\/\/www.quora.com\/When-should-you-fsync-the-containing-directory-in-addition-to-the-file-itself\">aqui<\/a><\/noindex> sobre isso pode-se ler em mais detalhes). Parece que o sistema de arquivos ext4 \u00e9 capaz de <noindex><a rel=\"nofollow\" href=\"https:\/\/lwn.net\/Articles\/799807\/\">automaticamente<\/a><\/noindex> aplicar <code>fsync()<\/code> a diret\u00f3rios que cont\u00eam arquivos correspondentes, mas no caso de outros sistemas de arquivos, isso pode n\u00e3o ser verdade.<\/p>\n<p>Esse mecanismo pode ser implementado de diferentes maneiras em diferentes sistemas de arquivos. Eu utilizei <noindex><a rel=\"nofollow\" href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/axboe\/blktrace.git\/tree\/README\">blktrace<\/a><\/noindex> para descobrir quais opera\u00e7\u00f5es de disco s\u00e3o utilizadas nos sistemas de arquivos ext4 e XFS. Ambos emitem comandos normais de grava\u00e7\u00e3o no disco tanto para o conte\u00fado dos arquivos quanto para o log do sistema de arquivos, limpam o cache e finalizam as opera\u00e7\u00f5es executando grava\u00e7\u00e3o FUA (Force Unit Access, grava\u00e7\u00e3o de dados diretamente no disco, ignorando o cache) no log. Provavelmente, agem dessa forma para confirmar o fato da realiza\u00e7\u00e3o da opera\u00e7\u00e3o. Em discos que n\u00e3o suportam FUA, isso causa duas limpezas de cache. Meus experimentos mostraram que <code>fdatasync()<\/code> um pouco mais r\u00e1pido <code>fsync()<\/code>. A ferramenta <code>blktrace<\/code> indica que <code>fdatasync()<\/code> geralmente grava menos dados no disco (no ext4 <code>fsync()<\/code> grava 20 KiB, enquanto <code>fdatasync()<\/code> \u2014 16 KiB). Al\u00e9m disso, descobri que o XFS \u00e9 um pouco mais r\u00e1pido que o ext4. E aqui, com o aux\u00edlio de <code>blktrace<\/code> foi poss\u00edvel descobrir que <code>fdatasync()<\/code> grava menos dados no disco (4 KiB no XFS).<\/p>\n<h2>Situa\u00e7\u00f5es amb\u00edguas que surgem ao usar fsync()<\/h2>\n<p>\nPosso lembrar de tr\u00eas situa\u00e7\u00f5es amb\u00edguas relacionadas <code>fsync()<\/code>, com as quais me deparei na pr\u00e1tica.<\/p>\n<p>O primeiro desses casos ocorreu em 2008. Naquele ano, a interface do Firefox 3 \"congelava\" quando uma grava\u00e7\u00e3o de muitos arquivos no disco era realizada. O problema era que na implementa\u00e7\u00e3o da interface, para armazenar informa\u00e7\u00f5es sobre seu estado, um banco de dados SQLite era utilizado. Ap\u00f3s cada altera\u00e7\u00e3o na interface, a fun\u00e7\u00e3o <code>fsync()<\/code>, o que proporcionava boas garantias de armazenamento persistente de dados. No sistema de arquivos ext3 usado na \u00e9poca, a fun\u00e7\u00e3o <code>fsync()<\/code> gravava no disco todas as p\u00e1ginas \"sujas\" do sistema, e n\u00e3o apenas aquelas que estavam relacionadas ao arquivo correspondente. Isso significava que um clique no bot\u00e3o no Firefox poderia iniciar a grava\u00e7\u00e3o de megabytes de dados no disco magn\u00e9tico, o que poderia levar muitos segundos. A solu\u00e7\u00e3o para o problema, pelo que entendi de <noindex><a rel=\"nofollow\" href=\"http:\/\/shaver.off.net\/diary\/2008\/05\/25\/fsyncers-and-curveballs\/\">disso<\/a><\/noindex> material, estava em mover o trabalho com o banco de dados para tarefas de fundo ass\u00edncronas. Isso significa que antes, no Firefox, eram implementados requisitos mais r\u00edgidos para a durabilidade do armazenamento de dados do que realmente eram necess\u00e1rios, e as particularidades do sistema de arquivos ext3 apenas agravaram esse problema.<\/p>\n<p>O segundo desvio ocorreu em 2009. Naquele ano, ap\u00f3s uma falha do sistema, os usu\u00e1rios do novo sistema de arquivos ext4 enfrentaram o problema de que muitos arquivos rec\u00e9m-criados tinham comprimento zero, enquanto isso n\u00e3o aconteceu com o sistema de arquivos mais antigo ext3. No par\u00e1grafo anterior, eu mencionei que o ext3 gravava muitos dados no disco, o que diminu\u00eda muito a performance <code>fsync()<\/code>. Para melhorar a situa\u00e7\u00e3o, no ext4, apenas as p\u00e1ginas \"sujas\" que est\u00e3o relacionadas a um arquivo espec\u00edfico s\u00e3o gravadas no disco. Os dados de outros arquivos permanecem na mem\u00f3ria por muito mais tempo do que com a aplica\u00e7\u00e3o do ext3. Isso foi feito para melhorar o desempenho (por padr\u00e3o, os dados permanecem nessa condi\u00e7\u00e3o por 30 segundos, e isso pode ser ajustado com <noindex><a rel=\"nofollow\" href=\"https:\/\/www.kernel.org\/doc\/Documentation\/sysctl\/vm.txt\">dirty_expire_centisecs<\/a><\/noindex>; <noindex><a rel=\"nofollow\" href=\"https:\/\/www.spinics.net\/lists\/linux-ext4\/msg68941.html\">aqui<\/a><\/noindex> , onde \u00e9 poss\u00edvel encontrar mais materiais sobre isso). Isso significa que uma grande quantidade de dados pode ser irremediavelmente perdida ap\u00f3s uma falha. A solu\u00e7\u00e3o para esse problema consiste em usar <code>fsync()<\/code> em aplica\u00e7\u00f5es que precisam garantir a durabilidade dos dados e maximizar sua prote\u00e7\u00e3o contra as consequ\u00eancias de falhas. A fun\u00e7\u00e3o <code>fsync()<\/code> funciona de forma muito mais eficaz com ext4 do que com ext3. A desvantagem dessa abordagem \u00e9 que sua aplica\u00e7\u00e3o, como antes, desacelera a execu\u00e7\u00e3o de algumas opera\u00e7\u00f5es, como a instala\u00e7\u00e3o de programas. Para mais detalhes sobre isso, veja <noindex><a rel=\"nofollow\" href=\"https:\/\/lwn.net\/Articles\/322823\/\">aqui<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/thunk.org\/tytso\/blog\/2009\/03\/12\/delayed-allocation-and-the-zero-length-file-problem\/\">aqui<\/a><\/noindex>.<\/p>\n<p>O terceiro problema, envolvendo <code>fsync()<\/code>, surgiu em 2018. Ent\u00e3o, no \u00e2mbito do projeto PostgreSQL, foi descoberto que se a fun\u00e7\u00e3o <code>fsync()<\/code> encontrar um erro, ela marca as p\u00e1ginas \"sujas\" como \"limpas\". Como resultado, as chamadas seguintes <code>fsync()<\/code> n\u00e3o se faz nada com essas p\u00e1ginas. Por causa disso, as p\u00e1ginas modificadas permanecem na mem\u00f3ria e nunca s\u00e3o gravadas no disco. Isso \u00e9 uma verdadeira cat\u00e1strofe, pois o aplicativo acreditar\u00e1 que alguns dados foram gravados no disco, quando na verdade n\u00e3o foram. Essas falhas <code>fsync()<\/code> s\u00e3o raras, o aplicativo em tais situa\u00e7\u00f5es quase nada pode fazer para combater o problema. Hoje em dia, quando isso acontece, o PostgreSQL e outros aplicativos encerram de forma abrupta. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.usenix.org\/conference\/atc20\/presentation\/rebello\">Aqui<\/a><\/noindex>, no material \"Os Aplicativos Podem se Recuperar de Falhas de fsync?\", esse problema \u00e9 investigado em detalhes. Atualmente, a melhor solu\u00e7\u00e3o para esse problema \u00e9 o uso de Direct I\/O com a flag <code>O_SYNC<\/code> ou com a flag <code>O_DSYNC<\/code>. Com essa abordagem, o sistema reportar\u00e1 erros que podem ocorrer durante a execu\u00e7\u00e3o de opera\u00e7\u00f5es de grava\u00e7\u00e3o de dados, mas essa abordagem requer que o aplicativo gerencie os buffers por conta pr\u00f3pria. Mais detalhes sobre isso podem ser lidos <noindex><a rel=\"nofollow\" href=\"https:\/\/lwn.net\/Articles\/752063\/\">aqui<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Fsync_Errors\">aqui<\/a><\/noindex>.<\/p>\n<h2>Abertura de arquivos utilizando as flags O_SYNC e O_DSYNC<\/h2>\n<p>\nVamos voltar \u00e0 discuss\u00e3o sobre os mecanismos do Linux que garantem a persist\u00eancia dos dados. Especificamente, isso se refere ao uso da flag <code>O_SYNC<\/code> ou da flag <code>O_DSYNC<\/code> ao abrir arquivos utilizando a chamada de sistema <noindex><a rel=\"nofollow\" href=\"https:\/\/man7.org\/linux\/man-pages\/man2\/open.2.html\">open()<\/a><\/noindex>. Com essa abordagem, cada opera\u00e7\u00e3o de grava\u00e7\u00e3o de dados \u00e9 executada como se, ap\u00f3s cada comando, <code>write()<\/code> o sistema recebesse, respectivamente, os comandos <code>fsync()<\/code> e <code>fdatasync()<\/code>. No <noindex><a rel=\"nofollow\" href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/009695399\/basedefs\/xbd_chap03.html#tag_03_373\">especifica\u00e7\u00e3o POSIX<\/a><\/noindex> isso \u00e9 chamado de \u201cConclus\u00e3o de Integridade de Arquivo de Entrada\/Sa\u00edda Sincronizada\u201d e \u201cConclus\u00e3o de Integridade de Dados\u201d. A principal vantagem dessa abordagem \u00e9 que, para garantir a integridade dos dados, \u00e9 necess\u00e1rio executar apenas uma chamada de sistema, em vez de duas (por exemplo \u2014 <code>write()<\/code> e <code>fdatasync()<\/code>). O principal inconveniente dessa abordagem \u00e9 que todas as opera\u00e7\u00f5es de grava\u00e7\u00e3o que usam o descritor de arquivo correspondente ser\u00e3o sincronizadas, o que pode limitar a capacidade de estruturar o c\u00f3digo do aplicativo.<\/p>\n<h2>O uso de Direct I\/O com a flag O_DIRECT<\/h2>\n<p>\nA chamada de sistema <code>open()<\/code> suporta a flag <code>O_DIRECT<\/code>, que \u00e9 projetada para realizar opera\u00e7\u00f5es de entrada\/sa\u00edda, interagindo diretamente com o disco, contornando o cache do sistema operacional. Isso, em muitos casos, significa que os comandos de grava\u00e7\u00e3o emitidos pelo programa ser\u00e3o diretamente traduzidos em comandos destinados a opera\u00e7\u00f5es no disco. Mas, em geral, esse mecanismo n\u00e3o substitui as fun\u00e7\u00f5es <code>fsync()<\/code> ou <code>fdatasync()<\/code>. O fato \u00e9 que o pr\u00f3prio disco pode <noindex><a rel=\"nofollow\" href=\"https:\/\/www.evanjones.ca\/durability-nvme.html\">adiar ou armazenar em cache<\/a><\/noindex> as correspondentes instru\u00e7\u00f5es de grava\u00e7\u00e3o de dados. E, o que \u00e9 ainda pior, em algumas situa\u00e7\u00f5es especiais, as opera\u00e7\u00f5es de entrada-sa\u00edda realizadas com a flag <code>O_DIRECT<\/code>, <noindex><a rel=\"nofollow\" href=\"https:\/\/ext4.wiki.kernel.org\/index.php\/Clarifying_Direct_IO%27s_Semantics\">s\u00e3o transmitidas<\/a><\/noindex> para opera\u00e7\u00f5es de buffer tradicionais. A solu\u00e7\u00e3o mais simples para esse problema \u00e9 usar tamb\u00e9m a flag ao abrir arquivos <code>O_DSYNC<\/code>, o que significa que ap\u00f3s cada opera\u00e7\u00e3o de grava\u00e7\u00e3o ser\u00e1 feita uma chamada <code>fdatasync()<\/code>.<\/p>\n<p>Descobriu-se que no sistema de arquivos XFS foi adicionada recentemente uma \"via r\u00e1pida\" para <code>O_DIRECT|O_DSYNC<\/code>-grava\u00e7\u00e3o de dados. Se um bloco \u00e9 regravado usando <code>O_DIRECT|O_DSYNC<\/code>, ent\u00e3o o XFS, ao inv\u00e9s de limpar o cache, executar\u00e1 o comando FUA de grava\u00e7\u00e3o caso o dispositivo o suporte. Verifiquei isso usando a ferramenta <code>blktrace<\/code> no sistema Linux 5.4\/Ubuntu 20.04. Essa abordagem deve ser mais eficiente, pois, ao us\u00e1-la, a quantidade m\u00ednima de dados \u00e9 gravada no disco e \u00e9 aplicada uma opera\u00e7\u00e3o, e n\u00e3o duas (grava\u00e7\u00e3o e limpeza do cache). Encontrei um link para <noindex><a rel=\"nofollow\" href=\"https:\/\/patchwork.kernel.org\/patch\/10250257\/\">patch<\/a><\/noindex> um kernel de 2018, no qual esse mecanismo foi implementado. H\u00e1 discuss\u00f5es sobre a aplica\u00e7\u00e3o dessa otimiza\u00e7\u00e3o em outros sistemas de arquivos, mas, at\u00e9 onde sei, o XFS \u00e9 o \u00fanico sistema de arquivos que a suporta.<\/p>\n<h2>A fun\u00e7\u00e3o sync_file_range()<\/h2>\n<p>\nNo Linux, existe uma chamada de sistema <noindex><a rel=\"nofollow\" href=\"https:\/\/man7.org\/linux\/man-pages\/man2\/sync_file_range.2.html\">sync_file_range()<\/a><\/noindex>, que permite gravar apenas uma parte do arquivo no disco, e n\u00e3o o arquivo inteiro. Essa chamada inicia uma grava\u00e7\u00e3o ass\u00edncrona de dados e n\u00e3o espera sua conclus\u00e3o. Mas, na documenta\u00e7\u00e3o, <code>sync_file_range()<\/code> essa instru\u00e7\u00e3o \u00e9 descrita como \"muito perigosa\". N\u00e3o \u00e9 recomendada. As caracter\u00edsticas e perigos <code>sync_file_range()<\/code> s\u00e3o muito bem descritos no <noindex><a rel=\"nofollow\" href=\"http:\/\/yoshinorimatsunobu.blogspot.com\/2014\/03\/how-syncfilerange-really-works.html\">isso<\/a><\/noindex> material. Em particular, aparentemente, essa chamada utiliza o RocksDB para gerenciar quando o kernel grava dados \"sujos\" no disco. Mas, para garantir o armazenamento resiliente de dados, <code>fdatasync()<\/code>. No <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/facebook\/rocksdb\/search?q=sync_file_range\">c\u00f3digo<\/a><\/noindex> H\u00e1 coment\u00e1rios interessantes sobre isso no RocksDB. Por exemplo, parece que a chamada <code>sync_file_range()<\/code> ao usar ZFS n\u00e3o leva \u00e0 grava\u00e7\u00e3o de dados no disco. A experi\u00eancia me diz que o c\u00f3digo raramente utilizado pode conter erros. Portanto, eu recomendaria n\u00e3o usar essa chamada de sistema a menos que seja absolutamente necess\u00e1rio.<\/p>\n<h2>Chamadas de sistema que ajudam a garantir o armazenamento resiliente de dados<\/h2>\n<p>\nCheguei \u00e0 conclus\u00e3o de que para realizar opera\u00e7\u00f5es de entrada\/sa\u00edda que garantam o armazenamento confi\u00e1vel de dados, pode-se usar tr\u00eas abordagens. Todas elas requerem a chamada da fun\u00e7\u00e3o <code>fsync()<\/code> para o diret\u00f3rio onde o arquivo foi criado. Aqui est\u00e3o essas abordagens:<\/p>\n<ol>\n<li>Chamada da fun\u00e7\u00e3o <code>fdatasync()<\/code> ou <code>fsync()<\/code> ap\u00f3s a fun\u00e7\u00e3o <code>write()<\/code> (\u00e9 melhor usar <code>fdatasync()<\/code>).<\/li>\n<li>Trabalhar com o descritor de arquivo aberto com a flag <code>O_DSYNC<\/code> ou <code>O_SYNC<\/code> (melhor \u2014 com a flag <code>O_DSYNC<\/code>).<\/li>\n<li>Uso do comando <code>pwritev2()<\/code> com a flag <code>RWF_DSYNC<\/code> ou <code>RWF_SYNC<\/code> (preferencialmente \u2014 com a flag <code>RWF_DSYNC<\/code>).<\/li>\n<\/ol>\n<p><\/p>\n<h2>Notas sobre desempenho<\/h2>\n<p>\nN\u00e3o realizei medi\u00e7\u00f5es detalhadas de desempenho dos v\u00e1rios mecanismos que pesquisei. As diferen\u00e7as que observei na velocidade de suas opera\u00e7\u00f5es s\u00e3o bastante pequenas. Isso significa que posso estar errado, e que em outras condi\u00e7\u00f5es o mesmo pode apresentar resultados diferentes. Primeiro, falarei sobre o que tem maior impacto no desempenho, e depois sobre o que tem um impacto menor.<\/p>\n<ol>\n<li>A reescrita de dados em um arquivo \u00e9 mais r\u00e1pida do que a anexa\u00e7\u00e3o de dados ao arquivo (o ganho de desempenho pode variar de 2 a 100%). Anexar dados a um arquivo requer altera\u00e7\u00f5es adicionais nos metadados do arquivo, mesmo ap\u00f3s a chamada do sistema <code>fallocate()<\/code>, mas a magnitude desse efeito pode variar. Recomendo, para garantir o melhor desempenho, chamar <code>fallocate()<\/code> para pr\u00e9-alocar o espa\u00e7o necess\u00e1rio. Depois, esse espa\u00e7o deve ser explicitamente preenchido com zeros e chamar <code>fsync()<\/code>. Isso faz com que os blocos correspondentes no sistema de arquivos sejam marcados como 'alocados', e n\u00e3o como 'n\u00e3o alocados'. Isso oferece uma pequena melhoria no desempenho (cerca de 2%). Al\u00e9m disso, em alguns discos, a primeira opera\u00e7\u00e3o de acesso a um bloco pode ser mais lenta do que as outras. Isso significa que preencher o espa\u00e7o com zeros pode levar a uma melhoria significativa (cerca de 100%) no desempenho. Em particular, isso pode ocorrer com discos <noindex><a rel=\"nofollow\" href=\"https:\/\/n2ws.com\/blog\/how-to-guides\/pre-warm-ebs-volumes-on-aws\">AWS EBS<\/a><\/noindex> (esses s\u00e3o dados n\u00e3o oficiais, n\u00e3o consegui confirmar). O mesmo se aplica ao armazenamento <noindex><a rel=\"nofollow\" href=\"https:\/\/cloud.google.com\/compute\/docs\/disks\/benchmarking-pd-performance\">GCP Persistent Disk<\/a><\/noindex> (e isso j\u00e1 \u00e9 informa\u00e7\u00e3o oficial, confirmada por testes). Outros especialistas observaram as mesmas <noindex><a rel=\"nofollow\" href=\"http:\/\/yoshinorimatsunobu.blogspot.com\/2009\/05\/overwriting-is-much-faster-than_28.html\">observa\u00e7\u00f5es<\/a><\/noindex>, relacionadas a diferentes discos.<\/li>\n<li>Quanto menos chamadas de sistema \u2014 maior o desempenho (o ganho pode ser de cerca de 5%). Parece que a chamada <code>open()<\/code> com a flag <code>O_DSYNC<\/code> ou a chamada <code>pwritev2()<\/code> com a flag <code>RWF_SYNC<\/code> \u00e9 mais r\u00e1pida do que a chamada <code>fdatasync()<\/code>Suspeito que a quest\u00e3o esteja no fato de que, com essa abordagem, o que conta \u00e9 que para resolver a mesma tarefa s\u00e3o feitas menos chamadas de sistema (uma chamada em vez de duas). Mas a diferen\u00e7a de desempenho \u00e9 muito pequena, ent\u00e3o voc\u00ea pode muito bem ignor\u00e1-la e usar no aplicativo o que n\u00e3o complicar\u00e1 sua l\u00f3gica.<\/li>\n<\/ol>\n<p>\nSe voc\u00ea est\u00e1 interessado no tema de armazenamento de dados sustent\u00e1vel \u2014 aqui est\u00e3o alguns materiais \u00fateis:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.scylladb.com\/2017\/10\/05\/io-access-methods-scylla\/\">M\u00e9todos de Acesso I\/O<\/a><\/noindex> \u2014 uma vis\u00e3o geral dos mecanismos de entrada\/sa\u00edda.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/lwn.net\/Articles\/457667\/\">Garantindo que os dados cheguem ao disco<\/a><\/noindex> \u2014 um relato sobre o que acontece com os dados ao ir do aplicativo para o disco.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.quora.com\/When-should-you-fsync-the-containing-directory-in-addition-to-the-file-itself\">Quando voc\u00ea deve fsync a diretoria contenedora<\/a><\/noindex> \u2014 a resposta para quando deve ser aplicado <code>fsync()<\/code> para diret\u00f3rios. Se eu resumir em duas palavras, \u00e9 que isso deve ser feito ao criar um novo arquivo, e a raz\u00e3o para essa recomenda\u00e7\u00e3o \u00e9 que no Linux pode haver muitas refer\u00eancias ao mesmo arquivo.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/bobsql.com\/sql-server-on-linux-forced-unit-access-fua-internals\/\">SQL Server no Linux: Internos do FUA<\/a><\/noindex> \u2014 aqui \u00e9 descrito como o armazenamento persistente de dados \u00e9 implementado no SQL Server na plataforma Linux. Existem algumas compara\u00e7\u00f5es interessantes entre chamadas de sistema do Windows e Linux. Estou quase certo de que foi gra\u00e7as a este material que soube sobre a otimiza\u00e7\u00e3o FUA do XFS.<\/li>\n<\/ul>\n<p>\nVoc\u00ea j\u00e1 perdeu dados que acreditava estarem seguros no disco?<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/ruvds.com\/ru-rub?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=perevod&amp;utm_content=ustojchivoe_xranenie_dannyx_i_fajlovye_api_linux#order\"><img decoding=\"async\" alt=\"Armazenamento de dados sustent\u00e1vel e APIs de arquivos Linux\" src=\"\/wp-content\/uploads\/2020\/10\/8bea3fc2b65a5a683655d9c15e153c93.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/ruvds.com\/ru-rub\/news\/read\/123?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=perevod&amp;utm_content=ustojchivoe_xranenie_dannyx_i_fajlovye_api_linux\"><img decoding=\"async\" alt=\"Armazenamento de dados sustent\u00e1vel e APIs de arquivos Linux\" src=\"\/wp-content\/uploads\/2020\/10\/d9fd0b1c09eb6e40944aee2d13ee4088.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/524172\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u042f, \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0435\u0431\u044f, \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u044e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0449\u0438. \u042f \u043d\u0430\u0447\u0430\u043b \u0441 \u0447\u0442\u0435\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 NVMe \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a\u0438\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0438, \u043a\u0430\u0441\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (\u0442\u043e \u0435\u0441\u0442\u044c \u2014 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0438 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e\u0441\u043b\u0435 \u0441\u0431\u043e\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b), \u0434\u0430\u044e\u0442 \u043d\u0430\u043c NMVe-\u0434\u0438\u0441\u043a\u0438. \u042f \u0441\u0434\u0435\u043b\u0430\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":98091,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-98090","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u042f, \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0435\u0431\u044f, \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u044e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0449\u0438.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0423\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0435 API Linux | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u042f, \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0435\u0431\u044f, \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u044e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0449\u0438.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-10-24T00:42:38+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-11-17T22:58:48+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Armazenamento sustent\u00e1vel de dados e API de arquivos Linux | ProHoster","description":"Eu, ao pesquisar a resili\u00eancia do armazenamento de dados em sistemas na nuvem, decidi me testar, me certificar de que entendo as coisas b\u00e1sicas.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0423\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0435 API Linux | ProHoster","og:description":"\u042f, \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0435\u0431\u044f, \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u044e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0449\u0438.","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ustojchivoe-hranenie-dannyh-i-fajlovye-api-linux","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-10-24T00:42:38+00:00","article:modified_time":"2020-11-17T22:58:48+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"98090","title":null,"description":null,"keywords":null,"keyphrases":{"focus":[],"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 10:05:49","updated":"2026-08-11 12:50:05","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/98090","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=98090"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/98090\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/98091"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=98090"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=98090"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=98090"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}