> will there not be potential contention when the "to" vertex is updated?
Ah, just re-read your post and you've already answered this. My apologies. Phill On Friday, September 23, 2016 at 4:51:50 PM UTC+1, Phillip Henry wrote: > > Hi, Luca. > > > How many GB? > > The input file is 22gb of text. > > > If the file is ordered ... > > You are only sorting by the first account. The second account can be > anywhere in the entire range. My understanding is that both vertices are > updated when an edge is written. If this is true, will there not be > potential contention when the "to" vertex is updated? > > > OGraphBatchInsert ... keeps everything in RAM before flushing > > I assume I will still have to write retry code in the event of a collision > (see above)? > > > You cna use support --at- orientdb.com ... > > Sent. > > Regards, > > Phill > > On Friday, September 23, 2016 at 4:06:49 PM UTC+1, l.garulli wrote: >> >> On 23 September 2016 at 03:50, Phillip Henry <phill...@gmail.com> wrote: >> >>> > How big is your file the sort cannot write? >>> >>> One bil-ee-on lines... :-P >>> >> >> How many GB? >> >> >>> > ...This should help a lot. >>> >>> The trouble is that the size of a block of contiguous accounts in the >>> real data is not-uniform (even if it might be with my test data). >>> Therefore, it is highly likely a contiguous block of account numbers will >>> span 2 or more batches. This will lead to a lot of contention. In your >>> example, if Account 2 spills over into the next batch, chances are I'll >>> have to rollback that batch. >>> >>> Don't you also have a problem that if X, Y, Z and W in your example are >>> account numbers in the next batch, you'll also get contention? Admittedly, >>> randomization doesn't solve this problem either. >>> >> >> If the file is ordered, you could have X threads (where X is the number >> of cores) that parse the file not sequentially. For example with 4 threads, >> you could start the parsing in this way: >> >> Thread 1, starts from 0 >> Thread 2, starts from length * 1/4 >> Thread 3, starts from length * 2/4 >> Thread 1, starts from length * 3/4 >> >> Of course the parsing should browse until the next LF+LR if it's a CSV. >> It requires some lines of code, but you could avoid many conflicts. >> >> >>> > you can use the special Batch Importer: OGraphBatchInsert >>> >>> Would this not be subject to the same contention problems? >>> At what point is it flushed to disk? (Obviously, it can't live in heap >>> forever). >>> >> >> It keeps everything in RAM before flushing. Up to a few hundreds of >> millions of vertices/edges should be fine if you have a lot of heap, like >> 58GB (and 4GB of DISKCACHE). It depends by the number of attributes you >> have. >> >> >>> > You should definitely using transactions with batch size of 100 items. >>> >>> I thought I read somewhere else (can't find the link at the moment) that >>> you said only use transactions when using the remote protocol? >>> >> >> This was true before v2.2. With v2.2 the management of the transaction is >> parallel and very light. Transactions work well with graphs because every >> addEdge() operation is 2 update and having a TX that works like a batch >> really helps. >> >> >>> >>> > Please use last 2.2.10. ... try to define 50GB of DISKCACHE and 14GB >>> of Heap >>> >>> Will do on the next run. >>> >>> > If happens again, could you please send a thread dump? >>> >>> I have the full thread dump but it's on my work machine so can't post it >>> in this forum (all access to Google Groups is banned by the bank so I am >>> writing this on my personal computer). Happy to email them to you. Which >>> email shall I use? >>> >> >> You cna use support --at- orientdb.com referring at this thread in the >> subject. >> >> >>> >>> Phill >>> >> >> >> Best Regards, >> >> Luca Garulli >> Founder & CEO >> OrientDB LTD <http://orientdb.com/> >> >> Want to share your opinion about OrientDB? >> Rate & review us at Gartner's Software Review >> <https://www.gartner.com/reviews/survey/home> >> >> >> >>> On Friday, September 23, 2016 at 7:41:29 AM UTC+1, l.garulli wrote: >>> >>>> On 23 September 2016 at 00:49, Phillip Henry <phill...@gmail.com> >>>> wrote: >>>> >>>>> Hi, Luca. >>>>> >>>> >>>> Hi Phillip. >>>> >>>> >>>>> I have: >>>>> >>>>> 4. sorting is an overhead, albeit outside of Orient. Using the Unix >>>>> sort command failed with "No space left on device". Oops. OK, so I ran my >>>>> program to generate the data again, this time it is ordered by the first >>>>> account number. Performance was much slower as there appeared to be a lot >>>>> of contention for this account (ie, all writes were contending for this >>>>> account, even if the other account had less contention). More randomized >>>>> data was faster. >>>>> >>>> >>>> How big is your file the sort cannot write? Anyway, if you have the >>>> accounts sorted, you should have transactions of about 100 items where the >>>> bank account and edges are in the same transaction. This should help a >>>> lot. >>>> Example: >>>> >>>> Account 1 -> Payment 1 -> Account X >>>> Account 1 -> Payment 2 -> Account Y >>>> Account 1 -> Payment 3 -> Account Z >>>> Account 2 -> Payment 1 -> Account X >>>> Account 2 -> Payment 1 -> Account W >>>> >>>> If the transaction batch is 5 (I suggest you to start with 100), all >>>> the operations are executed in one transaction. In another thread has: >>>> >>>> Account 99 -> Payment 1 -> Account W >>>> >>>> It could go in conflict because the shared Account W. >>>> >>>> If you can export Account's IDs that are numbers and incremental, you >>>> can use the special Batch Importer: OGraphBatchInsert. Example: >>>> >>>> OGraphBatchInsert batch = new OGraphBatchInsert("plocal:/temp/mydb", >>>> "admin", "admin"); >>>> batch.begin(); >>>> >>>> batch.createEdge(0L, 1L, null); // CREATE EDGES BETWEEN VERTEX 0 and 1. IF >>>> VERTICES >>>> >>>> // DON'T EXISTS, ARE CREATED IMPLICITELY >>>> batch.createEdge(1L, 2L, null); >>>> batch.createEdge(2L, 0L, null); >>>> >>>> >>>> batch.createVertex(3L); // CREATE AN NON CONNECTED VERTEX >>>> >>>> >>>> Map<String, Object> vertexProps = new HashMap<String, Object>(); >>>> vertexProps.put("foo", "foo"); >>>> vertexProps.put("bar", 3); >>>> batch.setVertexProperties(0L, vertexProps); // SET PROPERTY FOR VERTEX 0 >>>> batch.end(); >>>> >>>> This is blazing fast, but uses Heap so run it with a lot of it. >>>> >>>> >>>>> >>>>> 6. I've mutlithreaded my loader. The details are now: >>>>> >>>>> - using plocal >>>>> - using 30 threads >>>>> - not using transactions (OrientGraphFactory.getNoTx) >>>>> >>>> >>>> You should definitely using transactions with batch size of 100 items. >>>> This speeds up things. >>>> >>>> >>>>> - retrying forever upon write collisions. >>>>> - using Orient 2.2.7. >>>>> >>>> >>>> Please use last 2.2.10. >>>> >>>> >>>>> - using -XX:MaxDirectMemorySize:258040m >>>>> >>>> >>>> This is not really important, it's just an upper bound for the JVM. >>>> Please set it to 512GB so you can forget about it. The 2 most important >>>> values are DISKCACHE and JVM heap. The sum must lower than the available >>>> RAM in the server before you run OrientDB. >>>> >>>> If you have 64GB, try to define 50GB of DISKCACHE and 14GB of Heap. >>>> >>>> If you use the Batch Importer, you should use more Heap and less >>>> DISKCACHE. >>>> >>>> >>>>> The good news is I've achieved an initial write throughput of about >>>>> 30k/second. >>>>> >>>>> The bad news is I've tried several runs and only been able to achieve >>>>> 200mil < number of writes < 300mil. >>>>> >>>>> The first time I tried it, the loader deadlocked. Using jstat showed >>>>> that the deadlock was between 3 threads at: >>>>> - >>>>> OOneKeyEntryPerKeyLockManager.acquireLock(OOneKeyEntryPerKeyLockManager.java:173) >>>>> - >>>>> OPartitionedLockManager.acquireExclusiveLock(OPartitionedLockManager.java:210) >>>>> - >>>>> OOneKeyEntryPerKeyLockManager.acquireLock(OOneKeyEntryPerKeyLockManager.java:171) >>>>> >>>> >>>> If happens again, could you please send a thread dump? >>>> >>>> >>>>> The second time it failed was due to a NullPointerException at >>>>> OByteBufferPool.java:297. I've looked at the code and the only way I can >>>>> see this happening is if OByteBufferPool.allocateBuffer throws an error >>>>> (perhaps an OutOfMemoryError in java.nio.Bits.reserveMemory). This >>>>> StackOverflow posting ( >>>>> http://stackoverflow.com/questions/8462200/examples-of-forcing-freeing-of-native-memory-direct-bytebuffer-has-allocated-us) >>>>> >>>>> seems to indicate that this can happen if the underlying >>>>> DirectByteBuffer's >>>>> Cleaner doesn't have its clean() method called. >>>>> >>>> >>>> This is because the database was bigger than this setting: - using >>>> -XX:MaxDirectMemorySize:258040m. Please set this at 512GB (see above). >>>> >>>> >>>>> Alternatively, I followed the SO suggestion and lowered the heap space >>>>> to a mere 1gb (it was 50gb) to make the GC more active. Unfortunately, >>>>> after a good start, the job is still running some 15 hours later with a >>>>> hugely reduced write throughput (~ 7k/s). Jstat shows 4292 full GCs >>>>> taking >>>>> a total time of 4597s - not great but not hugely awful either. At this >>>>> rate, the remaining 700mil or so payments are going to take another 30 >>>>> hours. >>>>> >>>> >>>> See above the suggested settings. >>>> >>>> >>>>> 7. Even with the highest throughput I have achieved, 30k writes per >>>>> second, I'm looking at about 20 hours of loading. We've taken the same >>>>> data >>>>> and, after trial and error that was not without its own problems, put it >>>>> into Neo4J in 37 minutes. This is a significant difference. It appears >>>>> that >>>>> they are approaching the problem differently to avoid contention on >>>>> updating the vertices during an edge write. >>>>> >>>> >>>> With all this suggestion you should be able to have much better >>>> numbers. If you can use the Batch Importer the number should be close to >>>> Neo4j. >>>> >>>> >>>>> >>>>> Thoughts? >>>>> >>>>> Regards, >>>>> >>>>> Phillip >>>>> >>>>> >>>> >>>> Best Regards, >>>> >>>> Luca Garulli >>>> Founder & CEO >>>> OrientDB LTD <http://orientdb.com/> >>>> >>>> Want to share your opinion about OrientDB? >>>> Rate & review us at Gartner's Software Review >>>> <https://www.gartner.com/reviews/survey/home> >>>> >>>> >>>> >>>> >>>>> >>>>> On Thursday, September 15, 2016 at 10:06:44 PM UTC+1, l.garulli wrote: >>>>>> >>>>>> On 15 September 2016 at 09:54, Phillip Henry <phill...@gmail.com> >>>>>> wrote: >>>>>> >>>>>>> Hi, Luca. >>>>>>> >>>>>> >>>>>> Hi Phillip, >>>>>> >>>>>> 3. Yes, default configuration. Apart from adding an index for >>>>>>> ACCOUNTS, I did nothing further. >>>>>>> >>>>>> >>>>>> Ok, so you have writeQuorum="majority" that means 2 sycnhronous >>>>>> writes and 1 asynchronous per transaction. >>>>>> >>>>>> >>>>>>> 4. Good question. With real data, we expect it to be as you suggest: >>>>>>> some nodes with the majority of the payments (eg, supermarkets). >>>>>>> However, >>>>>>> for the test data, payments were assigned randomly and, therefore, >>>>>>> should >>>>>>> be uniformly distributed. >>>>>>> >>>>>> >>>>>> What's your average in terms of number of edges? <10, <50, <200, >>>>>> <1000? >>>>>> >>>>>> >>>>>>> 2. Yes, I tried plocal minutes after posting (d'oh!). I saw a good >>>>>>> improvement. It started about 3 times faster and got faster still >>>>>>> (about 10 >>>>>>> times faster) by the time I checked this morning on a job running >>>>>>> overnight. However, even though it is now running at about 7k >>>>>>> transactions >>>>>>> per second, a billion edges is still going to take about 40 hours. So, >>>>>>> I >>>>>>> ask myself: is there anyway I can make it faster still? >>>>>>> >>>>>> >>>>>> Here it's missing the usage of AUTO-SHARDING INDEX. Example: >>>>>> >>>>>> accountClass.createIndex("Account.number", >>>>>> OClass.INDEX_TYPE.UNIQUE.toString(), (OProgressListener) null, >>>>>> (ODocument) null, >>>>>> "AUTOSHARDING", new String[] { "number" }); >>>>>> >>>>>> In this way you should go more in parallel, because the index is >>>>>> distributed across all the shards (clusters) of Account class. you >>>>>> should >>>>>> have 32 of them by default because you have 32 cores. >>>>>> >>>>>> Please let me know if by sorting the from_accounts and with this >>>>>> change if it's much faster. >>>>>> >>>>>> This is the best you can have out of the box. To push numbers up it's >>>>>> slightly more complicated: you should be sure that transactions go in >>>>>> parallel and they aren't serialized. This is possible by playing with >>>>>> internal OrientDB settings (mainly the distributed workerThreads), by >>>>>> having many clusters per class (You could try with 128 first and see how >>>>>> it's going). >>>>>> >>>>>> >>>>>>> I assume when I start the servers up in distributed mode once more, >>>>>>> the data will then be distributed across all nodes in the cluster? >>>>>>> >>>>>> >>>>>> That's right. >>>>>> >>>>>> >>>>>>> 3. I'll return to concurrent, remote inserts when this job has >>>>>>> finished. Hopefully, a smaller batch size will mean there is no >>>>>>> degradation >>>>>>> in performance either... FYI: with a somewhat unscientific approach, I >>>>>>> was >>>>>>> polling the server JVM with JStack and saw only a single thread doing >>>>>>> all >>>>>>> the work and it *seemed* to spend a lot of its time in ODirtyManager on >>>>>>> collection manipulation. >>>>>>> >>>>>> >>>>>> I think it's because you didn't use the AUTO-SHARDING index. >>>>>> Furthermore running distributed, unfortunately, means the tree ridbag is >>>>>> not available (we will support it in the future), so every change to the >>>>>> edges takes a lot of CPU to demarshall and marshall the entire edge list >>>>>> everytime you update a vertex. That's why my recommendation about >>>>>> sorting >>>>>> the vertices. >>>>>> >>>>>> >>>>>>> I totally appreciate that performance tuning is an empirical >>>>>>> science, but do you have any opinions as to which would probably be >>>>>>> faster: >>>>>>> single-threaded plocal or multithreaded remote? >>>>>>> >>>>>> >>>>>> With v2.2 yo can go in parallel, by using the tips above. For sure >>>>>> the replication has a cost. I'm sure you can go much faster with just >>>>>> one >>>>>> node and then start the other 2 nodes to have the database replicated >>>>>> automatically. At least for the first massive insertion. >>>>>> >>>>>> >>>>>>> >>>>>>> Regards, >>>>>>> >>>>>>> Phillip >>>>>>> >>>>>> >>>>>> Luca >>>>>> >>>>>> >>>>>> >>>>>>> >>>>>>> On Wednesday, September 14, 2016 at 3:48:56 PM UTC+1, Phillip Henry >>>>>>> wrote: >>>>>>>> >>>>>>>> Hi, guys. >>>>>>>> >>>>>>>> I'm conducting a proof-of-concept for a large bank (Luca, we had a >>>>>>>> 'phone conf on August 5...) and I'm trying to bulk insert a humongous >>>>>>>> amount of data: 1 million vertices and 1 billion edges. >>>>>>>> >>>>>>>> Firstly, I'm impressed about how easy it was to configure a >>>>>>>> cluster. However, the performance of batch inserting is bad (and seems >>>>>>>> to >>>>>>>> get considerably worse as I add more data). It starts at about 2k >>>>>>>> vertices-and-edges per second and deteriorates to about 500/second >>>>>>>> after >>>>>>>> only about 3 million edges have been added. This also takes ~ 30 >>>>>>>> minutes. >>>>>>>> Needless to say that 1 billion payments (edges) will take over a week >>>>>>>> at >>>>>>>> this rate. >>>>>>>> >>>>>>>> This is a show-stopper for us. >>>>>>>> >>>>>>>> My data model is simply payments between accounts and I store it in >>>>>>>> one large file. It's just 3 fields and looks like: >>>>>>>> >>>>>>>> FROM_ACCOUNT TO_ACCOUNT AMOUNT >>>>>>>> >>>>>>>> In the test data I generated, I had 1 million accounts and 1 >>>>>>>> billion payments randomly distributed between pairs of accounts. >>>>>>>> >>>>>>>> I have 2 classes in OrientDB: ACCOUNTS (extending V) and PAYMENT >>>>>>>> (extending E). There is a UNIQUE_HASH_INDEX on ACCOUNTS for the >>>>>>>> account >>>>>>>> number (a string). >>>>>>>> >>>>>>>> We're using OrientDB 2.2.7. >>>>>>>> >>>>>>>> My batch size is 5k and I am using the "remote" protocol to connect >>>>>>>> to our cluster. >>>>>>>> >>>>>>>> I'm using JDK 8 and my 3 boxes are beefy machines (32 cores each) >>>>>>>> but without SSDs. I wrote the importing code myself but did nothing >>>>>>>> 'clever' (I think) and used the Graph API. This client code has been >>>>>>>> given >>>>>>>> lots of memory and using jstat I can see it is not excessively GCing. >>>>>>>> >>>>>>>> So, my questions are: >>>>>>>> >>>>>>>> 1. what kind of performance can I realistically expect and can I >>>>>>>> improve what I have at the moment? >>>>>>>> >>>>>>>> 2. what kind of degradation should I expect as the graph grows? >>>>>>>> >>>>>>>> Thanks, guys. >>>>>>>> >>>>>>>> Phillip >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>> >>>>>>> --- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "OrientDB" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>> send an email to orient-databa...@googlegroups.com. >>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>> >>>>>> >>>>>> -- >>>>> >>>>> --- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "OrientDB" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to orient-databa...@googlegroups.com. >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> >>>> -- >>> >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "OrientDB" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to orient-databa...@googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> -- --- You received this message because you are subscribed to the Google Groups "OrientDB" group. To unsubscribe from this group and stop receiving emails from it, send an email to orient-database+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.