{"id":13836759,"url":"https://github.com/synrc/cr","last_synced_at":"2025-04-08T01:32:37.251Z","repository":{"id":28697150,"uuid":"32217418","full_name":"synrc/cr","owner":"synrc","description":"💠 CR: Chain Replication Database for KVS","archived":false,"fork":false,"pushed_at":"2018-06-12T08:37:45.000Z","size":210,"stargazers_count":57,"open_issues_count":1,"forks_count":15,"subscribers_count":20,"default_branch":"master","last_synced_at":"2024-04-14T04:22:44.624Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://synrc.com/apps/cr/doc/cr.htm","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/synrc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-14T15:05:23.000Z","updated_at":"2023-04-11T10:35:06.000Z","dependencies_parsed_at":"2022-08-29T01:11:19.519Z","dependency_job_id":null,"html_url":"https://github.com/synrc/cr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synrc%2Fcr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synrc%2Fcr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synrc%2Fcr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synrc%2Fcr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/synrc","download_url":"https://codeload.github.com/synrc/cr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246531968,"owners_count":20792736,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T15:00:53.913Z","updated_at":"2025-04-08T01:32:36.993Z","avatar_url":"https://github.com/synrc.png","language":"Erlang","funding_links":[],"categories":["Erlang"],"sub_categories":[],"readme":"Byzantine Chain Replication Database\n====================================\n\n[![Join the chat at https://gitter.im/spawnproc/cr](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spawnproc/cr?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nIn banking system demands are very tight. Database\nshould be at least tripled, stand-by nodes should pick up\nmaster reads from failover node, writes should be\naccepted on a reasonable quorum, failover must be followed by recovery, database\nshould be able to scale even with the RAM/DISC limitations.\n\nNo data should be treated as written otherwise that commited to all replicas.\nAll this circumstances leads us to chain replication protocol as a simple and natural\nfeedback to this challenge.\n\nDifferent replication techniques exists to satisfy replication demands.\nMaster-slave replication is most widely known type of replication\nused before in such products like GFS, HDFS, mongodb, etc. Quorum Intersection\nis another technique used in databases like Cassandra or Amazon Dynamo.\nThey mostly provide a consistent distributed repository\nfor event tables or for file storage. In banking industry\nwe synchronize account balances and need simple and managable\nprotocol for storage consistency issuing high demand on system integrity.\n\nThere are several classes of error usually implied when dealing with failure detection.\nThe most weak class is fail-stop events, when the outage is normal or predictable.\nThe second class is crash-failures, the ubnormal terminations and outages. The most strong\ntype of failures are byzantine failures resistant to bit-flips,\nhacked parties or any types of compromising the transaction objects.\nFor banking applications the byzantine fault tolerance is desired,\ndespite it affects the latency.\n\nFeatures\n--------\n\n* Highly-available CP database :-)\n* 2N+1 nodes tolerates N failures\n* Consistent hashing DHT\n* RAFT for managing server configurations timeline\n* HMAC signing for Byzantine capabilities\n* Various database backends: \u003cb\u003emnesia\u003c/b\u003e, \u003cb\u003eriak\u003c/b\u003e, \u003cb\u003eredis\u003c/b\u003e, \u003cb\u003efs\u003c/b\u003e, \u003cb\u003esql\u003c/b\u003e\n* High-performance non-blocking TCP acceptor\n* Separate endpoints for HEART, CLIENT and SERVER protocols\n* Pure, clean and understandable codebase\n* Article about CR implementation details: http://synrc.space/apps/cr/doc/cr.htm\n* Business Processing Erlang book: http://synrc.space/apps/bpe/doc/book.pdf\n\nLaunch\n------\n\n```bash\nmake console NAME=cr\nmake console NAME=cr2\nmake console NAME=cr3\n```\n\nYou could start all nodes in separate console sesions or you\ncan `make start NAME=cr2` nodes and later attach to them with `make attach NAME=cr2`.\nAlso the start is compatible within single folders, which cause no single problem.\n\n```erlang\n\u003e timer:tc(cr,test,[500]).\n\n=INFO REPORT==== 7-Apr-2015::00:56:34 ===\ncr:Already in Database: 14020\nNew record will be applied: 500\n{214369,{transactions,11510}}\n```\n\nFore generating sample data, let say 500 transactions you may run with `cr:test(500)`.\nBy measuring accepring performance it's like `2000 Req/s`.\n\n```erlang\n\u003e cr:dump().\n\n                                               vnode   i  n        top     latency\n    121791803110908576516973736059690251637994378581   1  1        391    2/198/64\n    243583606221817153033947472119380503275988757162   2  1        400    2/183/72\n    365375409332725729550921208179070754913983135743   3  1        388    3/195/64\n    487167212443634306067894944238761006551977514324   4  1        357    2/183/53\n    608959015554542882584868680298451258189971892905   5  2      12994    2/198/67\n    730750818665451459101842416358141509827966271486   6  2      13017    3/184/66\n    852542621776360035618816152417831761465960650067   7  2      13019    2/201/75\n    974334424887268612135789888477522013103955028648   8  2      13020    3/178/62\n   1096126227998177188652763624537212264741949407229   9  3      13021    2/190/68\n   1217918031109085765169737360596902516379943785810  10  3      13028    3/206/65\n   1339709834219994341686711096656592768017938164391  11  3      13030    2/208/55\n   1461501637330902918203684832716283019655932542972  12  3      13031    2/185/58\nok\n```\n\nThe latency in last column `~70 ms` means the moment data is stored on all `mnesia` replicas.\nThe latency in a given example is for storing async_dirty using KVS\nchain linking (from `1 to 3` msg per write operation, from `1 to 2` msg for lookups)\nclustered in `3 nodes` with same replicas number.\n\nLet's say we want to see all the operations log of a given replica `391`.\n\n```erlang\n\u003e cr:dump(391).\n                                         operation         id       prev    i       size\n                      transaction:389:feed::false:        391        387    1        480\n                      transaction:399:feed::false:        387        382    1        500\n                      transaction:375:feed::false:        382        379    1        446\n                      transaction:373:feed::false:        379        378    1        446\n                      transaction:383:feed::false:        378        376    1        473\n                      transaction:392:feed::false:        376        374    1        500\n                      transaction:360:feed::false:        374        371    1        446\n                      transaction:366:feed::false:        371        370    1        473\n                      transaction:370:feed::false:        370        369    1        446\n                      transaction:371:feed::false:        369        368    1        446\nok\n```\n\nYou may check this from the other side. First retrieve the operation and then\nretrieve the transaction created during operation.\n\n```erlang\n\u003e kvs:get(operation,391).\n{ok,#operation{id = 391,version = undefined,container = log,\n               feed_id = {121791803110908576516973736059690251637994378581,1},   % VNODE\n               prev = 387,next = undefined,feeds = [],guard = false,\n               etc = undefined,\n               body = {prepare,{\u003c0.41.0\u003e,{1428,358105,840469}},\n                               [{121791803110908576516973736059690251637994378581,1},  % SIGNATURES\n                                {608959015554542882584868680298451258189971892905,2}],\n                               #transaction{id = 389,version = undefined,container = feed,\n                                            feed_id = undefined,prev = undefined,next = undefined,\n                                            feeds = [],guard = false,etc = undefined,\n                                            timestamp = undefined,beneficiary = undefined,...}},\n               name = prepare,status = pending}}\n```\n\nThe transaction. For linking transaction to the link you should use full XA\nprotocol with two-stage confirmation (1) the PUT operation followed\nwith (2) LINK operation to some feed, such as user account or customer admin list.\n\n```erlang\n\u003e kvs:get(transaction,389).\n{ok,#transaction{id = 389,version = undefined,\n                 container = feed, feed_id = undefined, prev = undefined,\n                 next = undefined, feeds = [], guard = false, etc = undefined,\n                 timestamp = [], beneficiary = [],\n                 subsidiary = [], amount = [],tax = [],\n                 ballance = [], currency = [],\n                 description = [], info = [],\n                 prevdate = [], rate = [], item = []}}\n```\n\nThe actiual Erlang business logic, banking transaction from `db` schema\napplication is stored under 389 id. So you can easlity grab it unlinked\nas it was stored as atomic PUT.\n\nLicenses\n--------\n\n* consensus protols 1) raft and 2) paxos are distributed under the terms of Apache 2.0 http://www.apache.org/licenses/LICENSE-2.0.html\n* cr itself is distributed under the DHARMA license: http://5ht.co/license.htm\n\nCredits\n-------\n\nCopyright (c) 2015 Synrc Research Center s.r.o.\n\n* Maxim Sokhatsky\n* Vladimir Kirillov\n* Sergey Klimenko\n* Valery Meleshkin\n* Victor Sovietov\n\nOM A HUM\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynrc%2Fcr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsynrc%2Fcr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynrc%2Fcr/lists"}