mirror of
https://github.com/dragonflydb/dragonfly
synced 2024-11-21 23:19:53 +00:00
docs(server): Start DF shared nothing design document.
This commit is contained in:
parent
25e700f39f
commit
c49e88899b
622
docs/coordinator.excalidraw
Normal file
622
docs/coordinator.excalidraw
Normal file
@ -0,0 +1,622 @@
|
||||
{
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 498,
|
||||
"versionNonce": 987480120,
|
||||
"isDeleted": false,
|
||||
"id": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "dotted",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 712.375,
|
||||
"y": 510.2500000000001,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"width": 307,
|
||||
"height": 30,
|
||||
"seed": 1029717964,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "U2-I9a2X4amHnB7NZFWGv"
|
||||
},
|
||||
{
|
||||
"id": "MJoeQ6ylkFi5Z7UCzD-r-",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "KpIRIBeGsT3yzCPp6jbEN",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "Qnatw_Uix7cMFwAuW1DkJ",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "TLS6mZEI7BXyUdiiYHdrg",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "h_hyKP8N7nmD1NiZNa3ez",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "CrT6zZ8CKm_MSDw-CmcPG",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1660733356396,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 389,
|
||||
"versionNonce": 1321365816,
|
||||
"isDeleted": false,
|
||||
"id": "U2-I9a2X4amHnB7NZFWGv",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 717.375,
|
||||
"y": 515.2500000000001,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 297,
|
||||
"height": 20,
|
||||
"seed": 1592449524,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1660733269433,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "coordinator",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"originalText": "coordinator"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 469,
|
||||
"versionNonce": 684925752,
|
||||
"isDeleted": false,
|
||||
"id": "BY5OdEEKT0Y_DTy9Zgr9C",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 714.375,
|
||||
"y": 217.41666666666669,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 77,
|
||||
"height": 192,
|
||||
"seed": 1621471436,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "MJoeQ6ylkFi5Z7UCzD-r-",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "KpIRIBeGsT3yzCPp6jbEN",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1660733316757,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 113,
|
||||
"versionNonce": 2140069448,
|
||||
"isDeleted": false,
|
||||
"id": "45U617mr0L9ob4mc7Xozt",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 724.875,
|
||||
"y": 171.0865384615385,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 56,
|
||||
"height": 40,
|
||||
"seed": 1285924468,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1660733195706,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "shard 1\n",
|
||||
"baseline": 34,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "shard 1\n"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 123,
|
||||
"versionNonce": 738921016,
|
||||
"isDeleted": false,
|
||||
"id": "vY-LnNlhD3qWMEtRPoU0t",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 840.4375,
|
||||
"y": 171.0865384615385,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 64,
|
||||
"height": 20,
|
||||
"seed": 817296972,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1660733195706,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "shard 2",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "shard 2"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 499,
|
||||
"versionNonce": 1256651064,
|
||||
"isDeleted": false,
|
||||
"id": "xvkm28eoejETjF3M78jpN",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 943.125,
|
||||
"y": 221.875,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 77,
|
||||
"height": 187,
|
||||
"seed": 1482008524,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "h_hyKP8N7nmD1NiZNa3ez",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "CrT6zZ8CKm_MSDw-CmcPG",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1660733356396,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 193,
|
||||
"versionNonce": 731710264,
|
||||
"isDeleted": false,
|
||||
"id": "H72xWL9unzb1mQiLvx7L4",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 950.125,
|
||||
"y": 176.7115384615385,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 63,
|
||||
"height": 20,
|
||||
"seed": 1704611020,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1660733195706,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "shard 3",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "shard 3"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 547,
|
||||
"versionNonce": 1963108408,
|
||||
"isDeleted": false,
|
||||
"id": "jj-MVcNrzcH0DbFFo9noF",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 833.9375,
|
||||
"y": 221.16666666666669,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 77,
|
||||
"height": 193,
|
||||
"seed": 1374694167,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "Qnatw_Uix7cMFwAuW1DkJ",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "TLS6mZEI7BXyUdiiYHdrg",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1660733333008,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "MJoeQ6ylkFi5Z7UCzD-r-",
|
||||
"type": "arrow",
|
||||
"x": 717.875,
|
||||
"y": 501.1682692307693,
|
||||
"width": 24,
|
||||
"height": 87,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 6593352,
|
||||
"version": 99,
|
||||
"versionNonce": 1021163848,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1660733308793,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-24,
|
||||
-44
|
||||
],
|
||||
[
|
||||
-3,
|
||||
-87
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"focus": -0.8341352911917994,
|
||||
"gap": 9.08173076923083
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "BY5OdEEKT0Y_DTy9Zgr9C",
|
||||
"focus": -0.13122256675640864,
|
||||
"gap": 4.751602564102598
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "KpIRIBeGsT3yzCPp6jbEN",
|
||||
"type": "arrow",
|
||||
"x": 752.875,
|
||||
"y": 419.1682692307693,
|
||||
"width": 16,
|
||||
"height": 90,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 1407934264,
|
||||
"version": 74,
|
||||
"versionNonce": 1205666632,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1660733316764,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
7,
|
||||
42
|
||||
],
|
||||
[
|
||||
-9,
|
||||
90
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "BY5OdEEKT0Y_DTy9Zgr9C",
|
||||
"focus": 0.3233993962204972,
|
||||
"gap": 9.751602564102598
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"focus": -0.8035367629216211,
|
||||
"gap": 1.0817307692308304
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "Qnatw_Uix7cMFwAuW1DkJ",
|
||||
"type": "arrow",
|
||||
"x": 837.875,
|
||||
"y": 506.1682692307693,
|
||||
"width": 7,
|
||||
"height": 83,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 1927132472,
|
||||
"version": 74,
|
||||
"versionNonce": 1840565576,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1660733325799,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
7,
|
||||
-83
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"focus": -0.191317746711659,
|
||||
"gap": 4.0817307692308304
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "jj-MVcNrzcH0DbFFo9noF",
|
||||
"focus": 0.4002005378587657,
|
||||
"gap": 9.001602564102598
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "TLS6mZEI7BXyUdiiYHdrg",
|
||||
"type": "arrow",
|
||||
"x": 872.875,
|
||||
"y": 423.1682692307693,
|
||||
"width": 13,
|
||||
"height": 82,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 247434040,
|
||||
"version": 76,
|
||||
"versionNonce": 1827860040,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1660733333013,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
9,
|
||||
41
|
||||
],
|
||||
[
|
||||
-4,
|
||||
82
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "jj-MVcNrzcH0DbFFo9noF",
|
||||
"focus": 0.38070164408537926,
|
||||
"gap": 9.001602564102598
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"focus": -0.02127803036140877,
|
||||
"gap": 5.0817307692308304
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "h_hyKP8N7nmD1NiZNa3ez",
|
||||
"type": "arrow",
|
||||
"x": 995.875,
|
||||
"y": 418.1682692307693,
|
||||
"width": 13,
|
||||
"height": 90,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 2138692424,
|
||||
"version": 57,
|
||||
"versionNonce": 178091592,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1660733348048,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
12,
|
||||
47
|
||||
],
|
||||
[
|
||||
-1,
|
||||
90
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "xvkm28eoejETjF3M78jpN",
|
||||
"focus": 0.19231425235177602,
|
||||
"gap": 9.293269230769283
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"focus": 0.7835976013538369,
|
||||
"gap": 2.0817307692308304
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "CrT6zZ8CKm_MSDw-CmcPG",
|
||||
"type": "arrow",
|
||||
"x": 957.875,
|
||||
"y": 502.1682692307693,
|
||||
"width": 18,
|
||||
"height": 91,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#15aabf",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 1991558200,
|
||||
"version": 58,
|
||||
"versionNonce": 1980388936,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1660733356402,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-11,
|
||||
-39
|
||||
],
|
||||
[
|
||||
7,
|
||||
-91
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"focus": 0.6245467021802061,
|
||||
"gap": 8.08173076923083
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "xvkm28eoejETjF3M78jpN",
|
||||
"focus": -0.23155463939046053,
|
||||
"gap": 2.2932692307692832
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
}
|
||||
],
|
||||
"appState": {
|
||||
"gridSize": null,
|
||||
"viewBackgroundColor": "#ffffff"
|
||||
},
|
||||
"files": {}
|
||||
}
|
91
docs/df-share-nothing.md
Normal file
91
docs/df-share-nothing.md
Normal file
@ -0,0 +1,91 @@
|
||||
# Dragonfly Architecture
|
||||
|
||||
Dragonfly is a modern replacement for memory stores like Redis and Memcached. It scales vertically on a single instance to support millions of requests per second. It is more memory efficient, has been designed with reliability in mind, and includes a better caching design.
|
||||
|
||||
## Threading model
|
||||
|
||||
Dragonfly uses a single process with a multiple-thread architecture. Each Dragonfly thread is indirectly assigned several responsibilities via fibers.
|
||||
|
||||
One such responsibility is handling incoming connections. Once a socket listener accepts a client connection, the connection spends its entire lifetime bound to a single thread inside a fiber. Dragonfly is written to be 100% non-blocking; it uses fibers to provide asynchronisity in each thread. One of the essential properties of asynchronisity is that a thread cannot be blocked as long as it has pending CPU tasks. Dragonfly preserves this property by wrapping each unit of execution context in a fiber; we wrap units of execution that can potentially be blocked on I/O. For example, a connection loop runs within a fiber; a function that writes a snapshot runs inside a fiber, and so on.
|
||||
|
||||
As a side comment - asynchronicity and parallelism are different terms. Nodejs, for example, provides asynchronous execution but is single-threaded. Similarly, each Dragonfly thread is asynchronous on its own; therefore, Dragonfly is responsive to incoming events even when it handles long-running commands like saving to disk or running Lua scripts.
|
||||
|
||||
|
||||
### Thread actors in DF
|
||||
|
||||
The DF in-memory database is sharded into `N` parts, where `N` is less or equal to the number of threads in the system. Each database shard is owned and accessed by a single thread.
|
||||
The same thread can handle TCP connections and simultaneously host a database shard.
|
||||
See the diagram below.
|
||||
|
||||
|
||||
<br>
|
||||
<img src="http://static.dragonflydb.io/repo-assets/thread-per-core.svg" border="0"/>
|
||||
|
||||
Here, our DF process spawns 4 threads, where threads 1 through 3 handle I/O (i.e., manage client connections) and threads 2 through 4 manage DB shards. Thread 2, for example, divides its CPU time between handling incoming requests and processing DB operations on the shard it owns.
|
||||
|
||||
So when we say that thread 1 is an I/O thread, we mean that Dragonfly can pin fibers that manage client connections to thread 1. In general, any thread can have many responsibilities that require CPU time; database management and connection handling are only two of those responsibilities.
|
||||
|
||||
|
||||
## Fibers
|
||||
|
||||
I suggest reading my [intro post](https://www.romange.com/2018/12/15/introduction-to-fibers-in-c-/) about `Boost.Fibers` to learn more about fibers.
|
||||
|
||||
By the way, I want to compliment `Boost.Fibers` library–it has been exceptionally well designed:
|
||||
it's unintrusive, lightweight, and efficient. Moreover, its default scheduler can be overidden. In the case of `helio`, the I/O library that powers Dragonfly, we overrode the `Boost.Fibers` scheduler to support shared-nothing architecture and integrate it with the I/O polling loop.
|
||||
|
||||
Importantly, fibers require bottom-up support in the application layer to preserve their asynchronisity. For example, in the snippet below, a blocking write into `fd` won't magically allow a fiber to preempt and switch to another fiber. No, the whole thread will be blocked.
|
||||
|
||||
|
||||
```cpp
|
||||
...
|
||||
write(fd, buf, 1000000);
|
||||
|
||||
...
|
||||
pthread_mutex_lock(...);
|
||||
|
||||
```
|
||||
|
||||
Similarly, with a `pthread_mutex_lock` call, the whole thread might be blocked, wasting precious CPU time.. Therefore, the Dragonfly code uses *fiber-friendly* primitives for I/O, communication, and coordination. These primitives are supplied by the `helio` and `Boost.Fibers` libraries.
|
||||
|
||||
## Life of a command request
|
||||
|
||||
This section explains how Dragonfly handles a command in the context of shared-nothing architecture. In most architectures used today, multi-threaded servers use mutex locks to protect their data structures, but Dragonfly does not. Why is this?
|
||||
|
||||
Inter-thread interactions in Dragonfly occur only via passing messages from thread to thread. For example, consider the following sequence diagram of handling a SET request:
|
||||
|
||||
|
||||
```uml
|
||||
@startuml
|
||||
|
||||
actor User as A1
|
||||
boundary connection as B1
|
||||
entity "Shard K" as E1
|
||||
A1 -> B1 : SET KEY VAL
|
||||
B1 -> E1 : SET KEY VAL / k = HASH(KEY) % N
|
||||
E1 -> B1 : OK
|
||||
B1 -> A1 : Response
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
<img src="https://www.plantuml.com/plantuml/svg/NOn12m8X48Nl_eh7Gb272Az1WGl2Wb6G5NGqLsW9PaBjqBzlL-lId6Q-zxvnFdD4dNCAlzKbA2bk_ABUnJS0U2OAFWzC9Msb29I7N3AWiNSNUvYckbeA9R7SOknX3QjFCFgAYzg9jd3zXx720njqodRp4IqmmrxegLe_7CnNLDDr3Ed9bC87"/>
|
||||
|
||||
Here, a connection fiber resides in a thread different from one that handles the `KEY` entity. We use hashing to decide which shard owns which key.
|
||||
|
||||
Another way to think of this flow is that a connection fiber serves as a coordinator for issuing transactional commands to other threads. In this simple example, the external "SET" command requires a single message passed from the coordinator to the destination shard thread. When we think of the Dragonfly model in the context of a single command request, I prefer to use the following diagram instead of the [one above](#thread-actors-in-df).
|
||||
|
||||
<br>
|
||||
<img src="http://static.dragonflydb.io/repo-assets/coordinator.svg" border="0"/>
|
||||
|
||||
Here, a coordinator (or connection fiber) might even reside on one of the threads that coincidently owns one of the shards. However, it iseasier to think of it as a separate entity that never directly accesses any shard data.
|
||||
|
||||
The coordinator serves as a virtualization layer that hides all the complexity of talking to multiple shards. It employs start-of-the-art algorithms to provide atomicity (and strict serializability) semantics for multi-key commands like "mset, mget, and blpop." It also offers strict serializability for Lua scripts and multi-command transactions.
|
||||
|
||||
Hiding such complexity is valuable to the end customer, but it comes with some CPU and latency costs. We believe the trade-off is worthwhile given the value that Dragonfly provides.
|
||||
|
||||
If you want to deep dive into Dragonfly architecture without the complexities of transactional code, it's worth checking [Midi Redis](https://github.com/romange/midi-redis/),
|
||||
which implements a toy backend supporting `PING`, `SET`, and `GET` [commands](https://github.com/romange/midi-redis/blob/main/server/main_service.cc#L239).
|
||||
|
||||
In fact, Dragonfly grew from that project; they share a common commit history.
|
||||
|
||||
By the way, to learn how to build even simpler TCP backends than `midi-redis`, `helio` library provides sample backends like these: [echo_server](https://github.com/romange/helio/blob/master/examples/echo_server.cc) and [ping_iouring_server.cc](https://github.com/romange/helio/blob/master/examples/pingserver/ping_iouring_server.cc). These backends reach millions of QPS on multi-core servers much like Dragonfly and midi-redis do.
|
579
docs/thread-per-core.excalidraw
Normal file
579
docs/thread-per-core.excalidraw
Normal file
@ -0,0 +1,579 @@
|
||||
{
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
"elements": [
|
||||
{
|
||||
"type": "text",
|
||||
"version": 158,
|
||||
"versionNonce": 1897755639,
|
||||
"isDeleted": false,
|
||||
"id": "N2nJ6OaFNRqcFW23SO0u2",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 714.625,
|
||||
"y": 507.5390625000001,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 90,
|
||||
"height": 20,
|
||||
"seed": 1339600844,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676475959,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "I/O thread",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "I/O thread"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 212,
|
||||
"versionNonce": 1838113753,
|
||||
"isDeleted": false,
|
||||
"id": "pZs66qxoJlWQcWuBsvAxk",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 829.125,
|
||||
"y": 509.4140625000001,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 90,
|
||||
"height": 20,
|
||||
"seed": 1172993740,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676475959,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "I/O thread",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "I/O thread"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 223,
|
||||
"versionNonce": 1421110391,
|
||||
"isDeleted": false,
|
||||
"id": "qhrDskacRkr-tNl2Q3atR",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 948.6875,
|
||||
"y": 508.02455357142867,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 90,
|
||||
"height": 20,
|
||||
"seed": 1936794996,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676504307,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "I/O thread",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "I/O thread"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 344,
|
||||
"versionNonce": 1641244985,
|
||||
"isDeleted": false,
|
||||
"id": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "dotted",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 712.375,
|
||||
"y": 537.2500000000001,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 431,
|
||||
"height": 30,
|
||||
"seed": 1029717964,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "U2-I9a2X4amHnB7NZFWGv"
|
||||
}
|
||||
],
|
||||
"updated": 1658676541606,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 239,
|
||||
"versionNonce": 1717412567,
|
||||
"isDeleted": false,
|
||||
"id": "U2-I9a2X4amHnB7NZFWGv",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 717.375,
|
||||
"y": 542.2500000000001,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 421,
|
||||
"height": 20,
|
||||
"seed": 1592449524,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676541606,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "message bus",
|
||||
"baseline": 14,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "jPwIU_a9_nxvuDFAcbzxM",
|
||||
"originalText": "message bus"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 315,
|
||||
"versionNonce": 208875257,
|
||||
"isDeleted": false,
|
||||
"id": "mBFE2wiT175ZxMSdmWcvQ",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 712.375,
|
||||
"y": 305.7916666666667,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 77,
|
||||
"height": 192,
|
||||
"seed": 352036980,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "tK1EcrkpG35slJ07z1dTT"
|
||||
}
|
||||
],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 194,
|
||||
"versionNonce": 181803287,
|
||||
"isDeleted": false,
|
||||
"id": "tK1EcrkpG35slJ07z1dTT",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 717.375,
|
||||
"y": 376.7916666666667,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 67,
|
||||
"height": 50,
|
||||
"seed": 1251432308,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "thread\n1",
|
||||
"baseline": 43,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "mBFE2wiT175ZxMSdmWcvQ",
|
||||
"originalText": "thread\n1"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 430,
|
||||
"versionNonce": 1426120247,
|
||||
"isDeleted": false,
|
||||
"id": "BY5OdEEKT0Y_DTy9Zgr9C",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 833.375,
|
||||
"y": 306.4166666666667,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 77,
|
||||
"height": 192,
|
||||
"seed": 1621471436,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "sIrssFTnnb9f1o26g1j88",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "sIrssFTnnb9f1o26g1j88"
|
||||
}
|
||||
],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 310,
|
||||
"versionNonce": 514622649,
|
||||
"isDeleted": false,
|
||||
"id": "sIrssFTnnb9f1o26g1j88",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 838.375,
|
||||
"y": 377.4166666666667,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 67,
|
||||
"height": 50,
|
||||
"seed": 711168500,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "thread\n2",
|
||||
"baseline": 43,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "BY5OdEEKT0Y_DTy9Zgr9C",
|
||||
"originalText": "thread\n2"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 76,
|
||||
"versionNonce": 1406533463,
|
||||
"isDeleted": false,
|
||||
"id": "45U617mr0L9ob4mc7Xozt",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 845.375,
|
||||
"y": 260.0865384615385,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 53,
|
||||
"height": 40,
|
||||
"seed": 1285924468,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "shard\nthread",
|
||||
"baseline": 34,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "shard\nthread"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 85,
|
||||
"versionNonce": 2081260953,
|
||||
"isDeleted": false,
|
||||
"id": "vY-LnNlhD3qWMEtRPoU0t",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 964.9375,
|
||||
"y": 260.0865384615385,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 53,
|
||||
"height": 40,
|
||||
"seed": 817296972,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "shard\nthread",
|
||||
"baseline": 34,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "shard\nthread"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 458,
|
||||
"versionNonce": 190540409,
|
||||
"isDeleted": false,
|
||||
"id": "xvkm28eoejETjF3M78jpN",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1062.125,
|
||||
"y": 310.875,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fa5252",
|
||||
"width": 77,
|
||||
"height": 187,
|
||||
"seed": 1482008524,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "nSQOBHdmN0bLo5OeoOD0P",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "nSQOBHdmN0bLo5OeoOD0P"
|
||||
}
|
||||
],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 337,
|
||||
"versionNonce": 2051102103,
|
||||
"isDeleted": false,
|
||||
"id": "nSQOBHdmN0bLo5OeoOD0P",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1067.125,
|
||||
"y": 379.375,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 67,
|
||||
"height": 50,
|
||||
"seed": 1058179828,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "thread\n4",
|
||||
"baseline": 43,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "xvkm28eoejETjF3M78jpN",
|
||||
"originalText": "thread\n4"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 156,
|
||||
"versionNonce": 1163506521,
|
||||
"isDeleted": false,
|
||||
"id": "H72xWL9unzb1mQiLvx7L4",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1074.125,
|
||||
"y": 265.7115384615385,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 53,
|
||||
"height": 40,
|
||||
"seed": 1704611020,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
"fontFamily": 1,
|
||||
"text": "shard\nthread",
|
||||
"baseline": 34,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "shard\nthread"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 510,
|
||||
"versionNonce": 1046208569,
|
||||
"isDeleted": false,
|
||||
"id": "jj-MVcNrzcH0DbFFo9noF",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 952.9375,
|
||||
"y": 310.1666666666667,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 77,
|
||||
"height": 193,
|
||||
"seed": 1374694167,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "NxhycN5eOsL0I52k0H-lh",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"id": "NxhycN5eOsL0I52k0H-lh",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"id": "NxhycN5eOsL0I52k0H-lh"
|
||||
}
|
||||
],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 391,
|
||||
"versionNonce": 1308367831,
|
||||
"isDeleted": false,
|
||||
"id": "NxhycN5eOsL0I52k0H-lh",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 957.9375,
|
||||
"y": 381.6666666666667,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fd7e14",
|
||||
"width": 67,
|
||||
"height": 50,
|
||||
"seed": 617412057,
|
||||
"groupIds": [
|
||||
"DYa5vdmfX68EvWPAq2Beo"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1658676546251,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "thread\n3",
|
||||
"baseline": 43,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "jj-MVcNrzcH0DbFFo9noF",
|
||||
"originalText": "thread\n3"
|
||||
}
|
||||
],
|
||||
"appState": {
|
||||
"gridSize": null,
|
||||
"viewBackgroundColor": "#ffffff"
|
||||
},
|
||||
"files": {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user