2013-02-25 2 views
2

Я пытаюсь вставить ~ 56,249,000 элементов в berkeleydb-JE. Я побежал DBCacheSize, чтобы получить некоторые статистические данные о моей базе данных:Вставка данных в BerkeleyDB-JE становится все медленнее и медленнее

java -jar je-5.0.34.jar DbCacheSize -records 56248699 -key 8 -data 20 

=== Environment Cache Overhead === 

3,155,957 minimum bytes 

To account for JE daemon operation and record locks, 
a significantly larger amount is needed in practice. 

=== Database Cache Size === 

Minimum Bytes Maximum Bytes Description 
--------------- --------------- ----------- 
    1,287,110,736 1,614,375,504 Internal nodes only 
    4,330,861,264 4,658,126,032 Internal nodes and leaf nodes 

=== Internal Node Usage by Btree Level === 

Minimum Bytes Maximum Bytes  Nodes Level 
--------------- --------------- ---------- ----- 
    1,269,072,064 1,592,660,160  632,008 1 
    17,837,712  21,473,424  7,101 2 
     198,448   238,896   79 3 
      2,512   3,024   1 4 

Я задал этот вопрос 2 года назад Optimizing a BerkeleyDB JE Database но я до сих пор не знаю, как я должен настроить свою среду от этих статистических данных?

Когда данные будут загружены, я буду единственным пользователем, имеющим доступ к базе данных: следует ли использовать транзакцию?

Мой окр в настоящее время открыт следующим образом:

EnvironmentConfig cfg=(...) 
cfg.setTransactional(true); 
cfg.setAllowCreate(true); 
cfg.setReadOnly(false); 
cfg.setCachePercent(80); 
cfg.setConfigParam(EnvironmentConfig.LOG_FILE_MAX,"250000000"); 

база данных:

cfg.setAllowCreate(true); 
cfg.setTransactional(true); 
cfg.setReadOnly(false); 

и я прочитал/вставить элементы следующим образом:

Transaction txn= env.beginTransaction(null, null); 
//open db with transaction 'txn' 
Database db=env.open(...txn) 

Transaction txn2=this.getEnvironment().beginTransaction(null, null); 
long record_id=0L; 
while((item=readNextItem(input))!=null) 
    { 
    (...) 
    ++record_id; 

    db.put(...); //insert record_id/item into db 
    /** every 100000 items commit and create a new transaction. 
     I found it was the only way to avoid an outOfMemory exception */ 
    if(record_id%100000==0) 
     { 
     txn2.commit(); 
     System.gc(); 
     txn2=this.getEnvironment().beginTransaction(null, null); 
     } 
    } 

txn2.commit(); 
txn.commit(); 

но вещи становятся медленнее и медленнее. Я запустил программу из eclipse, не установив ничего для JVM.

100000/56248699 (0.2 %). 13694.9 records/seconds. Time remaining:68.3 m Disk Usage: 23.4 Mb. Expect Disk Usage: 12.8 Gb Free Memory : 318.5 Mb. 
200000/56248699 (0.4 %). 16680.6 records/seconds. Time remaining:56.0 m Disk Usage: 49.5 Mb. Expect Disk Usage: 13.6 Gb Free Memory : 338.3 Mb. 
(...) 
6600000/56248699 (11.7 %). 9658.2 records/seconds. Time remaining:85.7 m Disk Usage: 2.9 Gb. Expect Disk Usage: 24.6 Gb Free Memory : 165.0 Mb. 
6700000/56248699 (11.9 %). 9474.5 records/seconds. Time remaining:87.2 m Disk Usage: 2.9 Gb. Expect Disk Usage: 24.7 Gb Free Memory : 164.8 Mb. 
6800000/56248699 (12.1 %). 9322.6 records/seconds. Time remaining:88.4 m Disk Usage: 3.0 Gb. Expect Disk Usage: 24.8 Gb Free Memory : 164.8 Mb. 
(Ctrl-C... abort...) 

Как я могу сделать вещи быстрее?

Update:

MemTotal:  4021708 kB 
MemFree:   253580 kB 
Buffers:   89360 kB 
Cached:   1389272 kB 
SwapCached:   56 kB 
Active:   2228712 kB 
Inactive:  1449096 kB 
Active(anon): 1793592 kB 
Inactive(anon): 596852 kB 
Active(file):  435120 kB 
Inactive(file): 852244 kB 
Unevictable:   0 kB 
Mlocked:    0 kB 
HighTotal:  3174028 kB 
HighFree:   57412 kB 
LowTotal:   847680 kB 
LowFree:   196168 kB 
SwapTotal:  4085756 kB 
SwapFree:  4068224 kB 
Dirty:    16320 kB 
Writeback:    0 kB 
AnonPages:  2199056 kB 
Mapped:   111280 kB 
Shmem:   191272 kB 
Slab:    58664 kB 
SReclaimable:  41448 kB 
SUnreclaim:  17216 kB 
KernelStack:  3792 kB 
PageTables:  11328 kB 
NFS_Unstable:   0 kB 
Bounce:    0 kB 
WritebackTmp:   0 kB 
CommitLimit:  6096608 kB 
Committed_AS: 5069728 kB 
VmallocTotal:  122880 kB 
VmallocUsed:  18476 kB 
VmallocChunk:  81572 kB 
HardwareCorrupted:  0 kB 
AnonHugePages:   0 kB 
HugePages_Total:  0 
HugePages_Free:  0 
HugePages_Rsvd:  0 
HugePages_Surp:  0 
Hugepagesize:  2048 kB 
DirectMap4k:  10232 kB 
DirectMap2M:  903168 kB 

обновление 2:

Max. Heap Size (Estimated): 872.94M 
Ergonomics Machine Class: server 
Using VM: Java HotSpot(TM) Server VM 

обновление 3:

используя советы Jerven, я получаю следующее представление:

(...) 
    6800000/56248699 (12.1 %). 13144.8 records/seconds. Time remaining:62.7 m Disk Usage: 1.8 Gb. Expect Disk Usage: 14.6 Gb Free Memory : 95.5 Mb. 
    (...) 

против моего предыдущего результат :

6800000/56248699 (12.1 %). 9322.6 records/seconds. Time remaining:88.4 m Disk Usage: 3.0 Gb. Expect Disk Usage: 24.8 Gb Free Memory : 164.8 Mb. 
+0

Не могли бы вы добавить свои JVM и детали машины. – Jerven

+0

Java (TM) SE Runtime Environment (build 1.7.0_07-b10) – Pierre

+0

Название Linux 3.2.0-38-generic-pae # 60-Ubuntu SMP Wed Feb 13 13:47:26 UTC 2013 i686 i686 i386 GNU/Linux – Pierre

ответ

2

Прежде всего, я бы удалил ваш явный вызов System.gc(); Если вы заметили, что эта полезность помогает рассмотреть другой алгоритм GC. Например, G1GC будет работать лучше, когда использование bdb/je кэша будет постоянно приближаться к 70% доступной кучи.

Во-вторых, в некоторый момент обновление индекса B + будет иметь значение n log n и уменьшит время вставки.

Не использовать транзакции будет быстрее. Особенно, если вы можете перезапустить импорт с нуля, если он не работает.

Просто не забудьте сделать environment.sync() и контрольную точку в конце. При этом вы можете отключить контрольную точку BDB/je и потоки GC BDB/je.

config.setConfigParam(EnvironmentConfig.ENV_RUN_CLEANER, "false"); 
config.setConfigParam(EnvironmentConfig.ENV_RUN_CHECKPOINTER, "false); 
config.setConfigParam(EnvironmentConfig.ENV_RUN_IN_COMPRESSOR, "false"); 

После загрузки вы должны вызвать метод, подобный этому.

public void checkpointAndSync() 
    throws ObjectStoreException 
{ 
      env.sync(); 
    CheckpointConfig force = new CheckpointConfig(); 
    force.setForce(true); 
    try 
    { 
     env.checkpoint(force); 
    } catch (DatabaseException e) 
    { 
     log.error("Can not chekpoint db " + path.getAbsolutePath(), e); 
     throw new ObjectStoreException(e); 
    } 
} 

Вы можете подумать, включив keyprefixing.

В остальном размер вашего внутреннего кеша узла должен быть не менее 1,6 ГБ, а это означает, что куча размером более 2 ГБ начнется.

Вы также можете рассмотреть вопрос о слиянии записей. Например, если ваши клавиши естественным образом увеличиваются, вы можете сохранить 16 значений под одним ключом. Но если вы считаете, что это интересный подход, вы можете начать с increasing the B tree fanout setting.

+0

Это ответ, который я бы принял и проголосовал. Красиво сделано. – duffymo

Смежные вопросы