From d88580a093e70f9254765f36f909fb310df77c5e Mon Sep 17 00:00:00 2001 From: randomJoe211 <69501902+randomJoe211@users.noreply.github.com> Date: Thu, 2 Sep 2021 00:12:45 +0800 Subject: [PATCH] Update service tuning docs --- docs-2.0/20.appendix/2.graph-modeling.md | 36 --------- docs-2.0/8.service-tuning/2.graph-modeling.md | 73 ++++++++++++++++++ docs-2.0/8.service-tuning/3.system-design.md | 40 ++++++++++ docs-2.0/8.service-tuning/4.plan.md | 5 ++ docs-2.0/8.service-tuning/compaction.md | 20 ++++- docs-2.0/8.service-tuning/load-balance.md | 9 +-- docs-2.0/8.service-tuning/sequence.png | Bin 0 -> 54110 bytes docs-2.0/8.service-tuning/super-node.md | 59 ++++++++++++++ 8 files changed, 197 insertions(+), 45 deletions(-) delete mode 100644 docs-2.0/20.appendix/2.graph-modeling.md create mode 100644 docs-2.0/8.service-tuning/2.graph-modeling.md create mode 100644 docs-2.0/8.service-tuning/3.system-design.md create mode 100644 docs-2.0/8.service-tuning/4.plan.md create mode 100644 docs-2.0/8.service-tuning/sequence.png create mode 100644 docs-2.0/8.service-tuning/super-node.md diff --git a/docs-2.0/20.appendix/2.graph-modeling.md b/docs-2.0/20.appendix/2.graph-modeling.md deleted file mode 100644 index 33f17a37ac7..00000000000 --- a/docs-2.0/20.appendix/2.graph-modeling.md +++ /dev/null @@ -1,36 +0,0 @@ -## Graph data modeling suggestions - -This section provides general suggestions for modeling data in Nebula Graph. - -!!! note - - The following suggestions may not apply to some special scenarios. In these cases, find help in the [Nebula Graph community](https://discuss.nebula-graph.io/). - -### Model for performance - -There is no perfect method to model in Nebula Graph. Graph modeling depends on the questions that you want to know from the data. Your data drives your graph model. Graph data modeling is intuitive and convenient. Create your data model based on your business model. Test your model and gradually optimize it to fit your business. To get better performance, you can change or re-design your model multiple times. - -### Edges as properties - -Traversal depth decreases the traversal performance. To decrease the traversal depth, use vertex properties instead of edges. - -For example, to model a graph that have the name, age, and eye color elements, you can: - -- (RECOMMENDED) Create a tag `person`, then add the name, age, and eye color as its properties. -- (WRONG WAY) Create a new tag `eye color` and a new edge type `has`, then create an edge to indicate that a person has an eye color. - -The first modeling solution leads to much better performance. DO NOT use the second solution unless you have to. - -Multiple properties under one tag are permitted. But make sure that tags are fine-grained. For more information, see the [Granulated vertices](#granulated_vertices) section. - -### Granulated vertices - -In graph modeling, use the data models with a higher level of granularity. Put a set of parallel properties into one tag, i.e., separate different concepts. - -### Use indexes correctly - -Correct use of indexes speeds up queries, but indexes reduce the write performance by 90% or more. **ONLY** use indexes when you locate vertices or edges by their properties. - -### No long string properties on edges - -Be careful when you create long string properties for edges. Nebula Graph supports storing such properties on edges. But note that these properties are stored both in the outgoing edges and the incoming edges. Thus be careful with the write amplification. diff --git a/docs-2.0/8.service-tuning/2.graph-modeling.md b/docs-2.0/8.service-tuning/2.graph-modeling.md new file mode 100644 index 00000000000..2ba351eafd6 --- /dev/null +++ b/docs-2.0/8.service-tuning/2.graph-modeling.md @@ -0,0 +1,73 @@ +## Graph data modeling suggestions + +This section provides general suggestions for modeling data in Nebula Graph. + +!!! note + + The following suggestions may not apply to some special scenarios. In these cases, find help in the [Nebula Graph community](https://discuss.nebula-graph.io/). + +### Model for performance + +There is no perfect method to model in Nebula Graph. Graph modeling depends on the questions that you want to know from the data. Your data drives your graph model. Graph data modeling is intuitive and convenient. Create your data model based on your business model. Test your model and gradually optimize it to fit your business. To get better performance, you can change or re-design your model multiple times. + +### Design and evaluate the most important queries + +Usually, various types of queries are validated in test scenarios to assess the overall capabilities of the system. However, in most production scenarios, there are not many types of frequently used queries. You can optimize the data model based on key queries selected according to the Pareto (80/20) principle. + +### No predefined bonds between Tags and Edge types + +Define the bonds between Tags and Edge types in the application, not Nebula Graph. There are no statements that could get the bonds between Tags and Edge types. + +### Tags/Edge types predefine a set of properties + +While creating Tags or Edge types, you need to define a set of properties. Properties are part of the Nebula Graph Schema. + +### Control changes in the business model and the data model + +Some graph databases are designed to be Schema-free, so their data modeling, including the modeling of the graph topology and properties, can be very flexible. Properties can be re-modeled to graph topology, and vice versa. Such systems are often specifically optimized for graph topology access. + +Nebula Graph {{ nebula.release }} is a strong-Schema (row storage) system, which means that the business model should not change frequently. For example, the property Schema should not change. It is similar to avoiding `ALTER TABLE` in MySQL. + +On the contrary, vertices and their edges can be added or deleted at low costs. Thus, the easy-to-change part of the business model should be transformed to vertices or edges, rather than properties. + +For example, in a business model, people have relatively fixed properties such as age, gender, and name. But their contact, place of visit, trade account, and login device are often changing. The former is suitable for modeling as properties and the latter as vertices or edges. + +### Breadth-first traversal over depth-first traversal + +Nebula Graph has lower performance for depth-first traversal based on the Graph topology, and better performance for breadth-first traversal and obtaining properties. For example, if model A contains properties "name", "age", and "eye color", it is recommended to create a Tag `person` and add properties `name`, `age`, and `eye_color` to it. If you create a Tag `eye_color` and an Edge type `has`, and then create an edge to represent the eye color owned by the person, the traversal performance will not be high. + +The performance of finding an edge by an edge property is close to that of finding a vertex by a vertex property. For some databases, it is recommended to re-model edge properties as those of the intermediate vertices. For example, model the pattern `(src)-[edge {P1, P2}]->(dst)` as `(src)-[edge1]->(i_node {P1, P2})-[edge2]->(dst)`. With Nebula Graph {{ nebula.release }}, you can use `(src)-[edge {P1, P2}]->(dst)` directly to decrease the depth of the traversal and increase the performance. + +### Edge directions + +To query in the opposite direction of an edge, use the syntax `(dst)<-[edge]-(src)` or `GO FROM dst REVERSELY`. + +If you don't care about the directions or want to query against both directions, use the syntax `(src)-[edge]-(dst)` or `GO FROM src BIDIRECT`. + +Therefore, there is no need to insert the same edge redundantly in the reversed direction. + +### Set Tag properties appropriately + +Put a group of properties that are on the same level into the same Tag. Different groups represent different concepts. + +### Use indexes correctly + +Using property indexes helps find VIDs through properties, but can lead to performance decrease by 90% or even more. Only use an index when you need to find vertices or edges through their properties. + +### Design VIDs appropriately + +See [VID](../1.introduction/3.vid.md). + +### Long texts + +Do not use long texts to create edge properties. Edge properties are stored twice and long texts lead to greater write amplification. For how edges properties are stored, see [Storage architecture](../1.introduction/3.nebula-graph-architecture/4.storage-service.md). It is recommended to store long texts in HBase or Elasticsearch and store its address in Nehula Graph. + +## Dynamic graphs (sequence graphs) are not supported + +In some scenarios, graphs need to have time information to describe how the structure of the entire graph changes over time.[^twitter] + +The Rank field on Edges in Nebula Graph {{ nebula.release }} can be used to store time in int64, but no field on vertices can do this because if you store the time information as property values, it will be covered by new insertion. Thus Nebula Graph does not support sequence graphs. + +![image](sequence.png) + +[^twitter]: https://blog.twitter.com/engineering/en_us/topics/insights/2021/temporal-graph-networks diff --git a/docs-2.0/8.service-tuning/3.system-design.md b/docs-2.0/8.service-tuning/3.system-design.md new file mode 100644 index 00000000000..1d3e720b435 --- /dev/null +++ b/docs-2.0/8.service-tuning/3.system-design.md @@ -0,0 +1,40 @@ +# System design suggestions + +## QPS or low-latency first + +Nebula Graph is good at handling small requests with high concurrency. In such scenarios, the whole graph is huge, containing maybe trillions of vertices, but the subgraphs accessed by each request are not large (containing millions of vertices or edges), and the latency of a single request is low. The concurrent number of such requests, i.e., the QPS, can be huge. + +On the other hand, in interactive analysis scenarios, the request concurrency is usually not high, but the subgraphs accessed by each request are large, with thousands of millions of vertices or edges. To lower the latency of big requests in such scenarios, you can split big requests into multiple small requests in the application, and send them to multiple Graph servers. This can decrease the memory used by each Graph server as well. Besides, you can use [Nebula Algorithm](../nebula-algorithm.md) for such scenarios. + +## Horizontal or vertical scaling + +Nebula Graph {{ nebula.release }} supports horizontal scaling. + ++ The horizontal scaling of the Storage Service: + + Increasing the number of Storage machines increases the overall capability of the cluster linearly, including increasing overall QPS and reducing latency. + + However, the number of partitions is fixed when creating a graph space. The service capability of a single partition is determined by a single server. The operations depending on a single partition include fetching properties of a single vertex (`FETCH`), a breadth-first traversal from a single vertex (`GO`), etc. + ++ The horizontal scaling of the Graph Service: + + Each request from the client is handled by one and only one Graph server, with no other Graph servers participating in the processing of the request. Therefore, increasing the number of Graph machines can increase the overall QPS of the cluster, but cannot lower the latency of a single request. + ++ Metad does not support horizontal scaling. + +Vertical scaling usually has higher hardware costs, but relatively simple operations. Nebula Graph {{Nebula. Release}} can also be scaled vertically. + +## Data transmission and optimization + +- Read/write balance. Nebula Graph fits into OLTP scenarios with balanced read/write, i.e., concurrent write and read. It is not suitable for OLAP scenarios that usually need to write once and read many times. +- Select different write methods. Write large batches of data with SST files, and small batches of data with `INSERT` statements. +- Run `COMPACTION` and `BALANCE` jobs to optimize data format and storage distribution at the right time. +- Nebula Graph {{ nebula.release }} N Does not support transactions and isolation in the relational database sense and is closer to NoSQL. + +## Query preheating and data preheating + +Preheat on the application side: + +- The Graph Service does not support pre-compiling queries and generating corresponding query plans, nor can it cache previous query results. +- The Storage Service does not support preheating data, and only the LSM-Tree and BloomFilter of RocksDB are loaded into memory at startup. +- Once accessed, vertices and edges are cached respectively in two types of LRU cache of the Storage Service. diff --git a/docs-2.0/8.service-tuning/4.plan.md b/docs-2.0/8.service-tuning/4.plan.md new file mode 100644 index 00000000000..4f693154a8b --- /dev/null +++ b/docs-2.0/8.service-tuning/4.plan.md @@ -0,0 +1,5 @@ +# Execution plan + +Nebula Graph {{ nebula.release }} applies rule-based execution plans. Users cannot change execution plans, precompile queries and corresponding plan cache, or accelerate queries by specifying indexes. + +To view the execution plan and executive summary, see [EXPLAIN and PROFILE](../3.ngql-guide/17.query-tuning-statements/1.explain-and-profile.md). diff --git a/docs-2.0/8.service-tuning/compaction.md b/docs-2.0/8.service-tuning/compaction.md index b8958210620..40e0bb894e5 100644 --- a/docs-2.0/8.service-tuning/compaction.md +++ b/docs-2.0/8.service-tuning/compaction.md @@ -12,7 +12,10 @@ Nebula Graph has two types of compaction: automatic compaction and full compacti ## Automatic compaction -Automatic compaction is done when the system reads data, writes data, or the system restarts. The automatic compaction is enabled by default. But once triggered during peak hours, it can cause unexpected IO occupancy that has an unwanted effect on the performance. To disable automatic compaction, use this statement: +Automatic compaction is done when the system reads data, writes data, or the system restarts. Automatic compaction is enabled by default. + + + ## Full compaction Full compaction enables large scale background operations for a graph space such as merging files, deleting the data expired by TTL. Use these statements to enable full compaction: @@ -45,15 +50,22 @@ nebula> SHOW JOB ; These are some operation suggestions to keep Nebula Graph performing well. + + - After data import is done, run `SUBMIT JOB COMPACT`. + - Run `SUBMIT JOB COMPACT` periodically during off-peak hours, for example, early morning. + + + +- To control the read and write traffic limitation for compactions, set the following parameter in the `nebula-storaged.conf` configuration file. ```bash - # read from the local configuration file and start - --local-config=true + # Limit the read/write rate to 20MB/s. --rate_limit=20 (in MB/s) ``` diff --git a/docs-2.0/8.service-tuning/load-balance.md b/docs-2.0/8.service-tuning/load-balance.md index de80488a4c1..8da38402081 100644 --- a/docs-2.0/8.service-tuning/load-balance.md +++ b/docs-2.0/8.service-tuning/load-balance.md @@ -35,7 +35,6 @@ nebual> SHOW HOSTS; +-------------+------+----------+--------------+-----------------------------------+------------------------+ | "Total" | | | 15 | "basketballplayer:15" | "basketballplayer:45" | +-------------+------+----------+--------------+-----------------------------------+------------------------+ -Got 6 rows (time spent 1002/1780 us) ``` Run `BALANCE DATA` to start balancing the storage partitions. If the partitions are already balanced, `BALANCE DATA` fails. @@ -47,7 +46,6 @@ nebula> BALANCE DATA; +------------+ | 1614237867 | +------------+ -Got 1 rows (time spent 3783/4533 us) ``` A BALANCE task ID is returned after running `BALANCE DATA`. Run `BALANCE DATA ` to check the status of the `BALANCE` task. @@ -67,7 +65,6 @@ nebula> BALANCE DATA 1614237867; +--------------------------------------------------------------+-------------------+ | "Total:22, Succeeded:22, Failed:0, In Progress:0, Invalid:0" | 100 | +--------------------------------------------------------------+-------------------+ -Got 23 rows (time spent 916/1528 us) ``` When all the subtasks succeed, the load balancing process finishes. Run `SHOW HOSTS` again to make sure the partition distribution is balanced. @@ -93,7 +90,6 @@ nebula> SHOW HOSTS; +-------------+------+----------+--------------+-----------------------------------+------------------------+ | "Total" | | | 15 | "basketballplayer:15" | "basketballplayer:45" | +-------------+------+----------+--------------+-----------------------------------+------------------------+ -Got 6 rows (time spent 849/1420 us) ``` If any subtask fails, run `BALANCE DATA` again to restart the balancing. If redoing load balancing does not solve the problem, ask for help in the [Nebula Graph community](https://discuss.nebula-graph.io/). @@ -116,6 +112,10 @@ Once all the subtasks are finished or stopped, you can run `BALANCE DATA` again * If no subtask of the preceding balance task failed, Nebula Graph starts a new balance task. +## RESET a balance task + +If a balance task fails to be restarted after being stopped, run `BALANCE DATA RESET PLAN` to reset the task. After that, run `BALANCE DATA` again to start a new balance task. + ## Remove storage servers To remove specific storage servers and scale in the Storage Service, use the `BALANCE DATA REMOVE ` syntax. @@ -145,7 +145,6 @@ Nebula Graph will start a balance task, migrate the storage partitions in storag ```ngql nebula> BALANCE LEADER; -Execution succeeded (time spent 7576/8657 us) ``` Run `SHOW HOSTS` to check the balance result. diff --git a/docs-2.0/8.service-tuning/sequence.png b/docs-2.0/8.service-tuning/sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..409e4688caf7ac75df0d076ddbcf824af4664b3c GIT binary patch literal 54110 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 literal 0 HcmV?d00001 diff --git a/docs-2.0/8.service-tuning/super-node.md b/docs-2.0/8.service-tuning/super-node.md new file mode 100644 index 00000000000..9e312bc7d16 --- /dev/null +++ b/docs-2.0/8.service-tuning/super-node.md @@ -0,0 +1,59 @@ +# Processing super vertices + +## Principle introduction + +In graph theory, a super vertex, also known as a dense vertex, is a vertex with an extremely high number of adjacent edges. The edges can be outgoing or incoming. + +Super vertices are very common because of the power-law distribution. For example, popular leaders in social networks (Internet celebrities), hot stocks in the stock market, four major banks in the banking system, hubs in transportation networks, high-traffic websites on the Internet, and on-fire products in E-commerce networks. + +In Nebula Graph, a vertex and its properties form a key-value pair, with the ID of the vertex and other meta information as the key. Its outgoing edges are stored with it in [the same partition](../1.introduction/3.nebula-graph-architecture/4.storage-service.md) in the form of different key-value pairs, and they are stored in LSM-trees in hard disks and caches. + +Therefore, directed traversals from this vertex and directed traversals ending at this vertex both involve either a large number of sequential IO scans (ideally, after compaction) or a large number of random IO (frequent writes to the vertex and its ingoing and outgoing edges). + +As a rule of thumb, a vertex is considered dense when the number of its edges exceeds 10,000. Some special cases require additional consideration。 + +### Indexes for duplicate properties + +In a property graph, there is another class of cases similar to super vertices: a property has a very high duplication rate, i.e., many vertices with the same Tag but different VIDs have identical property and property values. + +Property indexes in Nebula Graph are designed to reuse the functionality of RocksDB in the Storage Service, in which case indexes are modeled as keys with the same prefix. If the lookup of a property fails to hit the cache, it is processed as a random seek and a sequential prefix scan on the hard disk to find the corresponding VID. After that, the graph is usually traversed from this vertex, so that another random read and sequential scan for the corresponding key-value of this vertex will be triggered. The higher the duplication rate, the larger the scan range. + +For more information about property indexes, see [How indexing works in Nebula Graph](https://nebula-graph.io/posts/how-indexing-works-in-nebula-graph/). + +Usually, special design and processing are required when the number of duplicate property values exceeds 10,000. + +### Suggested solutions + +#### Solutions at the database end + +1. [Truncation](../5.configurations-and-logs/1.configurations/4.storage-config.md): Only return a certain number (a threshold) of edges, and do not return other edges exceeding this threshold. +2. [Compact](../8.service-tuning/compaction.md): Reorganize the order of data in RocksDB to reduce random reads and increase sequential reads. + +#### Solutions at the application end + +Break up some of the super vertices according to their business significance: + +- Delete multiple edges and merge them into one. + + For example, A transfer scenario is `(Account_A)-[TRANSFER]->(Account_B)`. Each transfer record is modeled as an edge between account A and account B, then there may be tens of thousands of transfer records. + + In such scenarios, merge obsolete transfer details on a daily, weekly, or monthly basis. That is, batch-delete old edges and replace them with a small number of edges representing monthly total and times. And keep the transfer details of the latest month. + +- Split an edge into multiple edges of different types. + + For example, in the `(Airport)<-[DEPART]-(Flight)` scenario, the departure of each flight is modeled as an edge between a flight and an airport. Departures from a big airport might be enormous. + + According to different airlines, divide the `DEPART` Edge type into finer Edge types, such as `DEPART_CEAIR`, `DEPART_CSAIR`, etc. Specify the departing airline in queries (graph traversal). + +- Split vertices. + +For example, for the loan network of `(person)-[BORROW]->(bank)`, large bank A will have a very large number of loans and borrowers. + +In such scenarios, you can split the large vertex A into connected sub-vertices A1, A2, and A3. + +```text +(Person1)-[BORROW]->(BankA1), (Person2)-[BORROW]->(BankA2), (Person2)-[BORROW]->(BankA3); +(BankA1)-[BELONGS_TO]->(BankA), (BankA2)-[BELONGS_TO]->(BankA), (BankA3)-[BELONGS_TO]->(BankA). +``` + +A1, A2, and A3 can either be three real branches of bank A, such as Beijing branch, Shanghai branch, and Zhejiang branch, or three virtual branches set up according to certain rules, such as `A1: 1-1000, A2: 1001-10000 and A3: 10000+` according to the number of loans. In this way, any operation on A is converted into three separate operations on A1, A2, and A3. \ No newline at end of file