Como faço para manter dados no disco, e tanto atualizá-lo de forma aleatória, e transmiti-lo de forma eficiente de volta para a RAM?

StackOverflow https://stackoverflow.com/questions/1274562

Pergunta

Eu preciso armazenar até dezenas ou mesmo centenas de milhões de peças de dados em disco. Cada pedaço de dados contém informações como:

id=23425
browser=firefox
ip-address=10.1.1.1
outcome=1.0

Novos partes de dados pode ser adicionado a uma taxa de up-a 1 por milissegundo.

Então, é um relativamente simples conjunto de pares chave-valor, onde os valores podem ser strings, inteiros, ou carros alegóricos. Ocasionalmente eu ser necessário atualizar o pedaço de dados com um determinado id, alterando o campo da bandeira de 0 a 1. Em outras palavras, eu preciso ser capaz de fazer pesquisas de chave aleatórias por id, e modificar os dados (na verdade, apenas o flutuante campo ponto "resultado." - então eu nunca mais vai precisar modificar o tamanho do valor)

O outro requisito é que eu preciso ser capaz de transmitir esses dados fora do disco (a ordem não é particularmente importante) de forma eficiente. Isto significa que a cabeça do disco rígido não deve necessidade de saltar em torno do disco para ler os dados, em vez disso, deve ser lido em blocos de disco consecutivos.

Eu estou escrevendo isso em Java.

Já pensou em usar um banco de dados integrado, mas DB4O não é uma opção, pois é GPL eo resto do meu código não é. I também se preocupam com a eficiência do uso de um banco de dados SQL integrado, dada a sobrecarga de traduzir de e para consultas SQL.

Alguém tem alguma idéia? Posso ter que construir uma solução personalizada para esta (onde eu estou lidando diretamente com ByteBuffers, e manusear o lookup id)?

Foi útil?

Solução 7

No final, eu decidi registrar os dados para o disco como se trata, e também mantê-lo na memória onde posso atualizá-lo. Após um período de tempo que eu escrever os dados no disco e apagar o registro.

Outras dicas

Como sobre H2 ? A Licença deve trabalhar para você.

  • Você pode usar H2 gratuitamente. Você pode integrá-lo em sua aplicação (Incluindo aplicações comerciais), e você pode distribuí-lo.
  • Arquivos contendo apenas o seu código não são coberto por esta licença (é 'Amigável comercial').
  • Modificações ao código-fonte H2 deve ser Publicados.
  • Você não precisa fornecer o código fonte do H2 se você não fez modificar nada.

I get

1000000 inserção em 22492ms (44460,252534234394 linha / seg)

100000 atualizações em 9565ms (10454,783063251438 linha / seg)

de

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;


/**
 * @author clint
 *
 */
public class H2Test {

  static int testrounds = 1000000;

  public static void main(String[] args) {
    try {
      Class.forName("org.h2.Driver");

    Connection conn = DriverManager.
        getConnection("jdbc:h2:/tmp/test.h2", "sa", "");
    // add application code here
    conn.createStatement().execute("DROP TABLE IF EXISTS TEST");
    conn.createStatement().execute("CREATE TABLE IF NOT EXISTS TEST(id INT PRIMARY KEY, browser VARCHAR(64),ip varchar(16), outcome real)"); 
    //conn.createStatement().execute("CREATE INDEX IDXall ON TEST(id,browser,ip,outcome");


    PreparedStatement ps = conn.prepareStatement("insert into TEST (id, browser, ip, outcome) values (?,?,?,?)");
    long time = System.currentTimeMillis();
    for ( int i = 0; i < testrounds; i++ ) {
      ps.setInt(1,i);
      ps.setString(2,"firefox");
      ps.setString(3,"000.000.000.000");
      ps.setFloat(4,0);
      ps.execute();
    }
    long last = System.currentTimeMillis() ;
    System.out.println( testrounds + " insert in " + (last - time) + "ms (" + ((testrounds)/((last - time)/1000d)) + " row/sec)" );

    ps.close();
    ps = conn.prepareStatement("update TEST set outcome = 1 where id=?");
    Random random = new Random();
    time = System.currentTimeMillis();

    /// randomly updadte 10% of the entries
    for ( int i = 0; i < testrounds/10; i++ ) {
      ps.setInt(1,random.nextInt(testrounds));
      ps.execute();
    }

    last = System.currentTimeMillis();
    System.out.println( (testrounds/10) + " updates in " + (last - time) + "ms (" + ((testrounds/10)/((last - time)/1000d)) + " row/sec)" );

    conn.close();

    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}

JDBM é um grande banco de dados integrado para Java (e não tão sobrecarregados com o licenciamento como a versão Java Berkley). Seria vale a pena tentar. Se você não precisa de garantias ACID (ou seja, você está OK com o banco de dados ficar corrompido em caso de um acidente), desligue o gerenciador de transações (aumenta significativamente a velocidade).

Eu acho que você tem muito mais sucesso escrita algo que mudanças armazena em cache os registros mais ativos na memória e filas de dados como uma baixa inserção prioridade para o DB.

Eu entendo que há um ligeiro aumento no IO usando este método, mas se você está falando de milhões de registros acho que ainda seria mais rápido porque qualquer algoritmo de busca que você criar vai ser muito superado por aa mecanismo de banco de pleno direito.

Você poderia tentar Berkley DB que agora é propriedade da Oracle . Eles têm Open Source e licenças comerciais. Ele usa um modelo de chave / valor (com uma opção para criar índices se são necessárias outras formas de consultas). Há uma versão Java puro e uma versão nativa com ligações Java.

http://www.zentus.com/sqlitejdbc/

banco de dados SQLite (domínio público), conector JDBC com a licença BSD, nativo para um monte de plataformas (OSX, Linux, Windows), emulação para o resto.

Você pode usar o Apache Derby (ou JavaDB) que vem com o JDK. No entanto, se um SGBD não fornecer a velocidade necessária você pode implementar uma estrutura de arquivo específico si mesmo. Se apenas lookup chave exata é necessária, você pode usar um arquivo de hash para implementá-lo. O arquivo hash é a estrutura do ficheiro mais rápido para tais requisitos (muito mais rapidamente do que as estruturas gerais de arquivo propósito, tais como B-Árvores e grelhas que são utilizados em bancos de dados). Ele também oferece eficiência de streaming aceitável.

Você deu uma olhada em banco de dados 'TimesTen' da Oracle? Sua db um in-memória que é suposto ser muito alto desempenho. Não sei sobre os custos / licenças, etc, mas dê uma olhada no site Oráculos e procurar por ela. Eval download deve estar disponível.

Eu também dar uma olhada para ver se há alguma coisa existente com base em ambos EHCache ou JCS que podem ajudar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top