{"id":383448,"date":"2024-06-29T04:55:06","date_gmt":"2024-06-29T04:55:06","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=383448"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=383448","title":{"rendered":"<span>\u041f\u0438\u0448\u0435\u043c \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430 \u043f\u043e\u043b\u0447\u0430\u0441\u0430<\/span>"},"content":{"rendered":"<div><!--[--><img loading=\"lazy\" decoding=\"async\" height=\"1\" src=\"https:\/\/www.facebook.com\/tr?id=981564558927545&amp;ev=Habr\" style=\"display:none;\" width=\"1\"><img loading=\"lazy\" decoding=\"async\" height=\"1\" src=\"https:\/\/www.facebook.com\/tr?id=1220899431627792&amp;ev=PageView&amp;noscript=1\" style=\"display:none;\" width=\"1\"><img loading=\"lazy\" decoding=\"async\" height=\"1\" src=\"https:\/\/top-fwz1.mail.ru\/counter?id=3200881;js=na\" style=\"display:none;\" width=\"1\"><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/6n\/9w\/q1\/6n9wq1hdfugltyfwr3e3ri9kvcy.png\" data-src=\"https:\/\/habrastorage.org\/webt\/6n\/9w\/q1\/6n9wq1hdfugltyfwr3e3ri9kvcy.png\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0418\u0433\u043e\u0440\u044c \u0438 \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 Tarantool. \u041f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043c\u043d\u0435 \u0447\u0430\u0441\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0438\u043b\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f MVP. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439 \u043f\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0435\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u043e \u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0440\u0430\u0431\u043e\u0442\u0443.<\/p>\n<p>  <\/p>\n<p>\u041c\u043d\u0435 \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 SQL \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0434\u0443\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u043e\u0432. \u0425\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u0447\u0435\u043a \u043a\u043e\u0434\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. \u0412 \u0431\u044b\u0441\u0442\u0440\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043c\u043d\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 Cartridge \u2014 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 NoSQL \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 Tarantool.<\/p>\n<p>  <\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Cartridge, \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c. \u0421\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0432\u0441\u0435\u043c, \u043a\u0442\u043e \u0443\u0441\u0442\u0430\u043b \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043b\u044e\u0434\u044f\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u044f\u0442 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e NoSQL \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044e.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"soderzhanie\">\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Cartridge \u0438 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0435\u0441\u044c \u0441 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u0432 \u043d\u0435\u043c.<\/p>\n<p>  <\/p>\n<p>\u041c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u0445 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u043d\u0430\u0441 \u0436\u0434\u0435\u0442:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0441 cartridge-cli<\/li>\n<li>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u043d\u0430 Lua \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u0445 \u0440\u043e\u043b\u044f\u0445 Cartridge<br \/> \n<ul>\n<li>\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/li>\n<li>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 HTTP API<\/li>\n<\/ul>\n<\/li>\n<li>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432<\/li>\n<li>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430<br \/> \n<ul>\n<li>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438<\/li>\n<li>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u0435\u0439\u043b\u043e\u0432\u0435\u0440\u0430<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"cartridge\">Cartridge<\/h2>\n<p>  <\/p>\n<p>Cartridge \u2014 \u044d\u0442\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043e\u043d \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430\u043c\u0438 NoSQL \u0411\u0414 Tarantool \u0438 \u0448\u0430\u0440\u0434\u0438\u0440\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0434\u0443\u043b\u044f vshard. Tarantool \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u0430\u044f in-memory \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u043d \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u2014 Tarantool \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0436\u0435\u0441\u0442\u043a\u0438\u0439 \u0434\u0438\u0441\u043a \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e, \u0430 Cartridge \u0441\u0430\u043c \u0437\u0430\u0431\u043e\u0442\u0438\u0442\u0441\u044f \u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0443\u0437\u043b\u043e\u0432 Tarantool \u0438 \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0443\u0437\u043b\u043e\u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u0441\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u2014 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0444\u0435\u0439\u043b\u043e\u0432\u0435\u0440\u0430.<\/p>\n<p>  <\/p>\n<h3 id=\"preimuschestva-sartridge\">\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0421artridge<\/h3>\n<p>  <\/p>\n<ul>\n<li>\u0428\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438<\/li>\n<li>\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 failover<\/li>\n<li>NoSQL \u044f\u0437\u044b\u043a \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u2014 CRUD<\/li>\n<li>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430<\/li>\n<li>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043e\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ansible<\/li>\n<li>\u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430<\/li>\n<li>\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430<\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"sozdaem-pervoe-prilozhenie\">\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0435\u0440\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f <a href=\"https:\/\/github.com\/tarantool\/cartridge-cli\">cartridge-cli<\/a> \u2014 \u044d\u0442\u043e \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u043d\u044b\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u041e\u043d\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043e\u043c \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043a \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430\u043c \u0442\u0430\u0440\u0430\u043d\u0442\u0443\u043b\u0430.<\/p>\n<p>  <\/p>\n<h3 id=\"ustanovim-tarantool-i-cartridge-cli\">\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c Tarantool \u0438 cartridge-cli<\/h3>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0430 Debian \u0438\u043b\u0438 Ubuntu:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">curl -L https:\/\/tarantool.io\/fJPRtan\/release\/2.8\/installer.sh | bash  sudo apt install cartridge-cli <\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0430 CentOS, Fedora \u0438\u043b\u0438 ALT Linux:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">curl -L https:\/\/tarantool.io\/fJPRtan\/release\/2.8\/installer.sh | bash  sudo yum install cartridge-cli <\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0430 MacOS:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">brew install tarantool  brew install cartridge-cli <\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c myapp:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cartridge create --name myapp  cd myapp  tree .<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">myapp \u251c\u2500\u2500 app \u2502 \u2514\u2500\u2500 roles \u2502 \u2514\u2500\u2500 custom.lua \u251c\u2500\u2500 test \u251c\u2500\u2500 init.lua \u251c\u2500\u2500 myapp-scm-1.rockspec<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><code>init.lua<\/code> \u2014 \u0432\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0435, \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/li>\n<li>\u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>app\/roles\/<\/code> \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f &#171;\u0440\u043e\u043b\u0438&#187;, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/li>\n<li><code>myapp-scm-1.rockspec<\/code> \u2014 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0448\u0430\u0433\u0435 \u0432\u044b \u0443\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 hello world-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0415\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cartridge build  cartridge start -d  cartridge replicasets setup --bootstrap-vshard<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>localhost:8081\/hello<\/code> \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c hello-world.<\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u2014 \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441 HTTP API \u0434\u043b\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u0430\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0432 Cartridge.<\/p>\n<p>  <\/p>\n<h2 id=\"pishem-biznes-logiku-v-cartridge\">\u041f\u0438\u0448\u0435\u043c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0432 Cartridge<\/h2>\n<p>  <\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0430\u0442 <strong>\u0440\u043e\u043b\u0438<\/strong> \u2014 Lua-\u043c\u043e\u0434\u0443\u043b\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u044d\u0442\u043e \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 HTTP API \u0438\u043b\u0438 \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 Oracle. \u0420\u043e\u043b\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439 (\u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442) \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u043d\u0438\u0445. \u0423 \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0440\u043e\u043b\u0435\u0439.<\/p>\n<p>  <\/p>\n<p>\u0412 cartridge \u0435\u0441\u0442\u044c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u0430\u044f <strong>\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u0443\u0437\u043b\u043e\u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430. \u0422\u0430\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0442\u0443\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0430\u0448\u0430 \u0440\u043e\u043b\u044c. \u0422\u0430\u043a\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435 \u0438 \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0440\u043e\u043b\u0438.<\/p>\n<p>  <\/p>\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u0440\u043e\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">return {     role_name = 'your_role_name',      init = init,     validate_config = validate_config,     apply_config = apply_config,     stop = stop,      rpc_function = rpc_function,     dependencies = {         'another_role_name',     }, }<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"zhiznennyy-cikl-roli\">\u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0440\u043e\u043b\u0438<\/h3>\n<p>  <\/p>\n<ol>\n<li>\u0418\u043d\u0441\u0442\u0430\u043d\u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f.<\/li>\n<li>\u0420\u043e\u043b\u044c \u0441 \u0438\u043c\u0435\u043d\u0435\u043c <code>role_name<\/code> \u0436\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432\u0441\u0435\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0440\u043e\u043b\u0435\u0439, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0432 <code>dependencies<\/code>.<\/li>\n<li>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>validate_config<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u0440\u043e\u043b\u0438.<\/li>\n<li>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u043e\u043b\u0438 <code>init<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 \u0440\u043e\u043b\u0438.<\/li>\n<li>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>apply_config<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433 (\u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0432\u043e\u0439 \u0438\u043c\u0435\u0435\u0442\u0441\u044f). <code>validate_config<\/code> \u0438 <code>apply_config<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0440\u043e\u043b\u0438.<\/li>\n<li>\u0420\u043e\u043b\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 registry, \u043e\u0442\u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u043e\u043b\u0435\u0439 \u043d\u0430 \u044d\u0442\u043e\u043c \u0436\u0435 \u0443\u0437\u043b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e<br \/>  <code>cartridge.service_get('your_role_name')<\/code>.<\/li>\n<li>\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0432 \u0440\u043e\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0441 \u0434\u0440\u0443\u0433\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e<br \/>  <code>cartridge.rpc_call('your_role_name', 'rpc_function')<\/code>.<\/li>\n<li>\u041f\u0435\u0440\u0435\u0434 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0440\u043e\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>stop<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0440\u043e\u043b\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0443\u0434\u0430\u043b\u044f\u044e\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u043e\u043b\u044c\u044e \u0444\u0430\u0439\u0431\u0435\u0440\u044b.<\/li>\n<\/ol>\n<p>  <\/p>\n<h2 id=\"klasternye-nosql-zaprosy\">\u041a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u0435 NoSQL-\u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/h2>\n<p>  <\/p>\n<p>\u0412 Cartridge \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<p>  <\/p>\n<ul>\n<li>\n<p>\u0412\u044b\u0437\u043e\u0432\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 API vshard (\u044d\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431, \u043d\u043e \u0437\u0430\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0433\u0438\u0431\u043a\u0438\u0439):<br \/>  <code>vshard.router.callrw(bucket_id, 'app.roles.myrole.my_rpc_func', {...})<\/code><\/p>\n<p>  <\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/tarantool\/crud\">Tarantool CRUD<\/a><\/p>\n<p>  <\/p>\n<ul>\n<li>\u041f\u0440\u043e\u0441\u0442\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <code>crud.insert<\/code> \/ <code>get<\/code> \/ <code>replace<\/code> \/ &#8230;<\/li>\n<li>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f <code>bucket_id<\/code><\/li>\n<li>\u0420\u043e\u043b\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 <code>crud-router<\/code> \/ <code>crud-storage<\/code><\/li>\n<\/ul>\n<p>  <\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"shema-prilozheniya\">\u0421\u0445\u0435\u043c\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0441 \u043e\u0434\u043d\u0438\u043c \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u043c \u0438 \u0441 \u0434\u0432\u0443\u043c\u044f \u0433\u0440\u0443\u043f\u043f\u0430\u043c\u0438 \u0441\u0442\u043e\u0440\u0430\u0434\u0436\u0435\u0439 \u043f\u043e \u0434\u0432\u0430 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430. \u0422\u0430\u043a\u0430\u044f \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430 \u0438 \u0434\u043b\u044f Redis Cluster, \u0438 \u0434\u043b\u044f Mongodb \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u2014 stateboard (\u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c stateful-failover \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043c\u0430\u0441\u0442\u0435\u0440\u043e\u0432). \u041a\u043e\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u043d\u0430\u044f \u043d\u0430\u0434\u0451\u0436\u043d\u043e\u0441\u0442\u044c, \u0432\u043c\u0435\u0441\u0442\u043e stateboard \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0442\u0435\u0440 etcd.<\/p>\n<p>  <\/p>\n<p>\u0420\u043e\u0443\u0442\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u0435\u0439\u043b\u043e\u0432\u0435\u0440\u043e\u043c.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/kv\/qj\/8d\/kvqj8dwnp7i-zlynp5cxt08fmmg.png\" data-src=\"https:\/\/habrastorage.org\/webt\/kv\/qj\/8d\/kvqj8dwnp7i-zlynp5cxt08fmmg.png\"\/><\/p>\n<p>  <\/p>\n<h2 id=\"pishem-svoi-roli\"><strong>\u041f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0438 \u0440\u043e\u043b\u0438<\/strong><\/h2>\n<p>  <\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0432\u0435 \u0441\u0432\u043e\u0438\u0445 \u0440\u043e\u043b\u0438, \u043e\u0434\u043d\u0443 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0432\u0442\u043e\u0440\u0443\u044e \u0434\u043b\u044f HTTP API.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 app\/roles \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u0430: <strong>app\/roles\/storage.lua<\/strong> \u0438 <strong>app\/roles\/api.lua<\/strong><\/p>\n<p>  <\/p>\n<h3 id=\"hranilische-dannyh\"><strong>\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/strong><\/h3>\n<p>  <\/p>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c \u0440\u043e\u043b\u044c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>init<\/code> \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0438 \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0434\u043b\u044f \u043d\u0435\u0435, \u0430 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c <code>crud-storage<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0440\u0438\u0432\u044b\u043a\u043b\u0438 \u043a SQL, \u0442\u043e Lua-\u043a\u043e\u0434 \u0432 init-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u0435\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043f\u0441\u0435\u0432\u0434\u043e-SQL \u043a\u043e\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">CREATE TABLE employee(     bucket_id unsigned,     employee_id string,     name string,     department string,     position string,     salary unsigned ); CREATE UNIQUE INDEX primary ON employee(employee_id); CREATE INDEX bucket_id ON employee(bucket_id);<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0432 \u0444\u0430\u0439\u043b <strong>app\/roles\/storage.lua<\/strong> :<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">local function init(opts)     -- \u0432 opts \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043f\u0440\u0438\u0437\u043d\u0430\u043a, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0430 \u043c\u0430\u0441\u0442\u0435\u0440\u0435 \u0438\u043b\u0438 \u043d\u0430 \u0440\u0435\u043f\u043b\u0438\u043a\u0435     -- \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043c\u0430\u0441\u0442\u0435\u0440\u0435, \u043d\u0430 \u0440\u0435\u043f\u043b\u0438\u043a\u0435 \u043e\u043d\u0438 \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438     if opts.is_master then         -- \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438         local employee = box.schema.space.create('employee', {if_not_exists = true})          -- \u0437\u0430\u0434\u0430\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442         employee:format({             {name = 'bucket_id', type = 'unsigned'},             {name = 'employee_id', type = 'string', comment = 'ID \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430'},             {name = 'name', type = 'string', comment = '\u0424\u0418\u041e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430'},             {name = 'department', type = 'string', comment = '\u041e\u0442\u0434\u0435\u043b'},             {name = 'position', type = 'string', comment = '\u0414\u043e\u043b\u0436\u043d\u043e\u0441\u0442\u044c'},             {name = 'salary', type = 'unsigned', comment = '\u0417\u0430\u0440\u043f\u043b\u0430\u0442\u0430'}         })          -- \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441         employee:create_index('primary', {parts = {{field = 'employee_id'}},             if_not_exists = true })          -- \u0418\u043d\u0434\u0435\u043a\u0441 \u043f\u043e bucket_id, \u043e\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f         employee:create_index('bucket_id', {parts = {{field = 'bucket_id'}},             unique = false,             if_not_exists = true })     end      return true end  return {     init = init,     -- &lt;&lt;&lt; \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 crud-storage     dependencies = {'cartridge.roles.crud-storage'}, }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0437 API \u0440\u043e\u043b\u0438 \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u2014 \u0443 \u043d\u0430\u0448\u0435\u0439 \u0440\u043e\u043b\u0438 \u043d\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u043e\u043d\u0430 \u043d\u0435 \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u0442 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0447\u0438\u0449\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b.<\/p>\n<p>  <\/p>\n<h3 id=\"http-api\"><strong>HTTP API<\/strong><\/h3>\n<p>  <\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u0430\u044f \u0440\u043e\u043b\u044c \u0434\u043b\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443. \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u043c\u0443 \u0432 Cartridge HTTP-\u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0438\u043c\u0435\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 <code>crud-router<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f POST-\u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0412 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0431\u0430\u0437\u0443.<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">local function post_employee(request)     -- \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     local employee = request:json()      -- \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432 \u0411\u0414     local _, err = crud.insert_object('employee', employee)      -- \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0438\u0448\u0435\u043c \u0435\u0435 \u0432 \u043b\u043e\u0433 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c 500     if err ~= nil then         log.error(err)         return {status = 500}     end     return {status = 200} end<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 GET-\u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0437\u0430\u0440\u043f\u043b\u0430\u0442\u044b \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c JSON \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u0437\u0430\u0440\u043f\u043b\u0430\u0442\u0443 \u0432\u044b\u0448\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0439.<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">SELECT employee_id, name, department, position, salary FROM employee WHERE salary >= @salary<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"lua\">local function get_employees_by_salary(request)     -- \u0434\u043e\u0441\u0442\u0430\u0435\u043c query-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 salary     local salary = tonumber(request:query_param('salary') or 0)      -- \u043e\u0442\u0431\u0438\u0440\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u0445     local employees, err = crud.select('employee', {{'>=', 'salary', salary}})      -- \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0438\u0448\u0435\u043c \u0435\u0435 \u0432 \u043b\u043e\u0433 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c 500     if err ~= nil then         log.error(err)         return { status = 500 }     end      -- \u0432 employees \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0440\u043e\u043a, \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0449\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043f\u0435\u0439\u0441\u0430     -- unflatten_rows \u043d\u0443\u0436\u043d\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0432\u0438\u0434\u0430 \u043a\u043b\u044e\u0447-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435     employees = crud.unflatten_rows(employees.rows, employees.metadata)      employees = fun.iter(employees):map(function(x)          return {             employee_id = x.employee_id,              name = x.name,              department = x.department,              position = x.position,              salary = x.salary,         }     end):totable()     return request:render({json = employees}) end<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c <code>init<\/code>-\u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0440\u043e\u043b\u0438. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a registry Cartridge \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f HTTP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0433\u043e \u0434\u043b\u044f \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f HTTP-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">local function init()     -- \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0438\u0437 registry Cartridge     local httpd = assert(cartridge.service_get('httpd'), \"Failed to get httpd serivce\")      -- \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0440\u043e\u0443\u0442\u044b     httpd:route({method = 'GET', path = '\/employees'}, get_employees_by_salary)     httpd:route({method = 'POST', path = '\/employee'}, post_employee)      return true end<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0431\u0435\u0440\u0435\u043c \u0432\u0441\u0435 \u044d\u0442\u043e \u0432\u043c\u0435\u0441\u0442\u0435:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">app\/roles\/api.lua<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"lua\">local cartridge = require('cartridge') local crud = require('crud') local log = require('log') local fun = require('fun')  -- \u043c\u0435\u0442\u043e\u0434 GET \/employees \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0441 \u0437\u0430\u0440\u043f\u043b\u0430\u0442\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0439 local function get_employees_by_salary(request)     -- \u0434\u043e\u0441\u0442\u0430\u0435\u043c query-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 salary     local salary = tonumber(request:query_param('salary') or 0)      -- \u043e\u0442\u0431\u0438\u0440\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u0445     local employees, err = crud.select('employee', {{'>=', 'salary', salary}})      -- \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0438\u0448\u0435\u043c \u0435\u0435 \u0432 \u043b\u043e\u0433 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c 500     if err ~= nil then         log.error(err)         return { status = 500 }     end      -- \u0432 employees \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0440\u043e\u043a, \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0449\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043f\u0435\u0439\u0441\u0430     -- unflatten_rows \u043d\u0443\u0436\u043d\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0432\u0438\u0434\u0430 \u043a\u043b\u044e\u0447-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435     employees = crud.unflatten_rows(employees.rows, employees.metadata)     employees = fun.iter(employees):map(function(x)          return {             employee_id = x.employee_id,              name = x.name,              department = x.department,              position = x.position,              salary = x.salary,         }     end):totable()     return request:render({json = employees}) end  local function post_employee(request)     -- \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430     local employee = request:json()      -- \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432 \u0411\u0414     local _, err = crud.insert_object('employee', employee)      -- \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0438\u0448\u0435\u043c \u0435\u0435 \u0432 \u043b\u043e\u0433 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c 500     if err ~= nil then         log.error(err)         return {status = 500}     end     return {status = 200} end  local function init()     -- \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0438\u0437 registry Cartridge     local httpd = assert(cartridge.service_get('httpd'), \"Failed to get httpd service\")      -- \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0440\u043e\u0443\u0442\u044b     httpd:route({method = 'GET', path = '\/employees'}, get_employees_by_salary)     httpd:route({method = 'POST', path = '\/employee'}, post_employee)      return true end  return {     init = init,     -- \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 crud-router     dependencies = {'cartridge.roles.crud-router'}, } <\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<h3 id=\"initlua\"><strong>init.lua<\/strong><\/h3>\n<p>  <\/p>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c \u0444\u0430\u0439\u043b <strong>init.lua<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Cartridge. \u0412 init-\u0444\u0430\u0439\u043b\u0435 \u043a\u0430\u0440\u0442\u0440\u0438\u0434\u0436\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <a href=\"https:\/\/www.tarantool.io\/ru\/doc\/latest\/book\/cartridge\/cartridge_api\/modules\/cartridge\/#cartridge-cfg\">cartridge.cfg()<\/a> \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430.<\/p>\n<p>  <\/p>\n<p><code>cartridge.cfg(&lt;opts>, &lt;box_opts>)<\/code><\/p>\n<p>  <\/p>\n<ul>\n<li><code>&lt;opts><\/code> \u2014 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<br \/> \n<ul>\n<li>\u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0440\u043e\u043b\u0435\u0439 (\u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0441\u0435 \u0440\u043e\u043b\u0438, \u0434\u0430\u0436\u0435 \u043f\u0435\u0440\u043c\u0430\u043d\u0435\u043d\u0442\u043d\u044b\u0435, \u0438\u043d\u0430\u0447\u0435 \u043e\u043d\u0438 \u043d\u0435 \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435)<\/li>\n<li>\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/li>\n<li>\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f WebUI<\/li>\n<li>\u0438 \u0434\u0440\u0443\u0433\u043e\u0435<\/li>\n<\/ul>\n<\/li>\n<li><code>&lt;box_opts><\/code> \u2014 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b Tarantool \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 box.cfg{} \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430)<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"lua\">#!\/usr\/bin\/env tarantool  require('strict').on()  -- \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 if package.setsearchroot ~= nil then     package.setsearchroot() end  -- \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c Cartridge local cartridge = require('cartridge')  local ok, err = cartridge.cfg({     roles = {         'cartridge.roles.vshard-storage',         'cartridge.roles.vshard-router',         'cartridge.roles.metrics',         -- &lt;&lt;&lt; \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c crud-\u0440\u043e\u043b\u0438         'cartridge.roles.crud-storage',         'cartridge.roles.crud-router',         -- &lt;&lt;&lt; \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0440\u043e\u043b\u0438         'app.roles.storage',         'app.roles.api',     },     cluster_cookie = 'myapp-cluster-cookie', })  assert(ok, tostring(err))<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>myapp-scm-1.rockspec<\/strong>.<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">package = 'myapp' version = 'scm-1' source  = {     url = '\/dev\/null', } -- \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 dependencies = {     'tarantool',     'lua >= 5.1',     'checks == 3.1.0-1',     'cartridge == 2.7.3-1',     'metrics == 0.11.0-1',     'crud == 0.8.0-1', } build = {     type = 'none'; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432 \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0438 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u043c\u0441\u044f \u0432 \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>  <\/p>\n<h2 id=\"pishem-testy\"><strong>\u041f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u044b<\/strong><\/h2>\n<p>  <\/p>\n<p>\u041b\u044e\u0431\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438. \u0414\u043b\u044f unit-\u0442\u0435\u0441\u0442\u043e\u0432 \u0445\u0432\u0430\u0442\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e luatest, \u043d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0442\u0435\u0441\u0442, \u0432\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043c\u043e\u0434\u0443\u043b\u044c cartridge.test-helpers. \u041e\u043d \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 Cartridge \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u043b\u044e\u0431\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0430\u043c \u043d\u0443\u0436\u0435\u043d.<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">local cartridge_helpers = require('cartridge.test-helpers') -- \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 local cluster = cartridge_helpers.Cluster:new({     server_command = '.\/init.lua', -- entrypoint \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f     datadir = '.\/tmp', -- \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0434\u043b\u044f xlog, snap \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432     use_vshard = true, -- \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430     -- \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442\u043e\u0432:     replicasets = {         {             alias = 'api',             uuid = cartridge_helpers.uuid('a'),             roles = {'app.roles.custom'}, -- \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u043b\u0435\u0439, \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u043d\u0430 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442             -- \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u0432 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442\u0435:             servers = {                 { instance_uuid = cartridge_helpers.uuid('a', 1), alias = 'api' },                 ...             },         },         ...     } })<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u0430\u0445. \u0412 \u043d\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0438\u0437 \u0434\u0432\u0443\u0445 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442\u043e\u0432, \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0443:<\/p>\n<p>  <\/p>\n<p>\u041a\u043e\u0434 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">test\/helper.lua<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"lua\">local fio = require('fio') local t = require('luatest') local cartridge_helpers = require('cartridge.test-helpers')  local helper = {}  helper.root = fio.dirname(fio.abspath(package.search('init'))) helper.datadir = fio.pathjoin(helper.root, 'tmp', 'db_test') helper.server_command = fio.pathjoin(helper.root, 'init.lua')  helper.cluster = cartridge_helpers.Cluster:new({     server_command = helper.server_command,     datadir = helper.datadir,     use_vshard = true,     replicasets = {         {             alias = 'api',             uuid = cartridge_helpers.uuid('a'),             roles = {'app.roles.api'},             servers = {                 { instance_uuid = cartridge_helpers.uuid('a', 1), alias = 'api' },             },         },         {             alias = 'storage',             uuid = cartridge_helpers.uuid('b'),             roles = {'app.roles.storage'},             servers = {                 { instance_uuid = cartridge_helpers.uuid('b', 1), alias = 'storage' },             },         },     } })  function helper.truncate_space_on_cluster(cluster, space_name)     assert(cluster ~= nil)     for _, server in ipairs(cluster.servers) do         server.net_box:eval([[             local space_name = ...             local space = box.space[space_name]             if space ~= nil and not box.cfg.read_only then                 space:truncate()             end         ]], {space_name})     end end  function helper.stop_cluster(cluster)     assert(cluster ~= nil)     cluster:stop()     fio.rmtree(cluster.datadir) end  t.before_suite(function()     fio.rmtree(helper.datadir)     fio.mktree(helper.datadir)     box.cfg({work_dir = helper.datadir}) end)  return helper <\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>\u041a\u043e\u0434 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">test\/integration\/api_test.lua<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"lua\">local t = require('luatest') local g = t.group('integration_api')  local helper = require('test.helper') local cluster = helper.cluster  g.before_all = function()     g.cluster = helper.cluster     g.cluster:start() end  g.after_all = function()     helper.stop_cluster(g.cluster) end  g.before_each = function()     helper.truncate_space_on_cluster(g.cluster, 'employee') end  g.test_get_employee = function()     local server = cluster.main_server      -- \u043d\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0447\u0435\u0440\u0435\u0437 HTTP API:     local response = server:http_request('post', '\/employee',         {json = {name = 'John Doe', department = 'Delivery', position = 'Developer',         salary = 10000, employee_id = 'john_doe'}})     t.assert_equals(response.status, 200)      response = server:http_request('post', '\/employee',         {json = {name = 'Jane Doe', department = 'Delivery', position = 'Developer',         salary = 20000, employee_id = 'jane_doe'}})     t.assert_equals(response.status, 200)      -- \u0414\u0435\u043b\u0430\u0435\u043c GET \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445     response = server:http_request('get', '\/employees?salary=15000.0')     t.assert_equals(response.status, 200)     t.assert_equals(response.json[1], {name = 'Jane Doe', department = 'Delivery', employee_id = 'jane_doe',         position = 'Developer', salary = 20000     }) end <\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<h2 id=\"zapuskaem-testy\"><strong>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b<\/strong><\/h2>\n<p>  <\/p>\n<h3 id=\"esli-vy-uzhe-zapuskali-prilozhenie\">\u0415\u0441\u043b\u0438 \u0432\u044b \u0443\u0436\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0435\u0433\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cartridge stop <\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u0434\u0430\u043b\u0438\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">rm -rf tmp\/ <\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">cartridge build  .\/deps.sh<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043b\u0438\u043d\u0442\u0435\u0440:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">.rocks\/bin\/luacheck .<\/code><\/pre>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/3f\/dm\/hw\/3fdmhwm-es2wo7ybqyeszi4mdnw.png\" data-src=\"https:\/\/habrastorage.org\/webt\/3f\/dm\/hw\/3fdmhwm-es2wo7ybqyeszi4mdnw.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0442\u0435\u0441\u0442\u044b \u0441 \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">.rocks\/bin\/luatest --coverage<\/code><\/pre>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/dz\/p9\/ww\/dzp9ww3zgwqurvvhmftikkm5uxk.png\" data-src=\"https:\/\/habrastorage.org\/webt\/dz\/p9\/ww\/dzp9ww3zgwqurvvhmftikkm5uxk.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0442\u0447\u0435\u0442\u044b \u043f\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">.rocks\/bin\/luacov . grep -A999 '^Summary' tmp\/luacov.report.out<\/code><\/pre>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/s3\/ya\/lf\/s3yalffnrsibgjobmbgeouqc1qu.png\" data-src=\"https:\/\/habrastorage.org\/webt\/s3\/ya\/lf\/s3yalffnrsibgjobmbgeouqc1qu.png\"\/><\/p>\n<p>  <\/p>\n<h2 id=\"lokalnyy-zapusk\"><strong>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/strong><\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f cartridge-cli, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u043c\u0438 \u0440\u043e\u043b\u0438 \u0432 replicasets.yml:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">router:   instances:   - router   roles:   - failover-coordinator   - app.roles.api   all_rw: false s-1:   instances:   - s1-master   - s1-replica   roles:   - app.roles.storage   weight: 1   all_rw: false   vshard_group: default s-2:   instances:   - s2-master   - s2-replica   roles:   - app.roles.storage   weight: 1   all_rw: false   vshard_group: default<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u044b\u0445 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0432 instances.yml.<\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">cartridge build cartridge start -d cartridge replicasets setup --bootstrap-vshard<\/code><\/pre>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ub\/zp\/ko\/ubzpkovqig0lgodmifqnorpthks.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ub\/zp\/ko\/ubzpkovqig0lgodmifqnorpthks.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0439\u0442\u0438 \u0432 webui \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0440\u043e\u043b\u0435\u0439, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0444\u0435\u0439\u043b\u043e\u0432\u0435\u0440. \u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c stateful failover, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 Failover<\/li>\n<li>\u0432\u044b\u0431\u0440\u0430\u0442\u044c stateful<\/li>\n<li>\u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0438 \u043f\u0430\u0440\u043e\u043b\u044c:<br \/> \n<ul>\n<li>localhost:4401<\/li>\n<li>passwd<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/2x\/3k\/re\/2x3kreyrnpsfbz1uojscuevu-wg.png\" data-src=\"https:\/\/habrastorage.org\/webt\/2x\/3k\/re\/2x3kreyrnpsfbz1uojscuevu-wg.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443. \u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442\u0435 <code>s-1<\/code> \u043b\u0438\u0434\u0435\u0440\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>s1-master<\/code>.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/21\/wc\/tl\/21wctlf_cxs3r5jvndsmhunn9jw.png\" data-src=\"https:\/\/habrastorage.org\/webt\/21\/wc\/tl\/21wctlf_cxs3r5jvndsmhunn9jw.png\"\/><\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0435\u0433\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">cartridge stop s1-master<\/code><\/pre>\n<p>  <\/p>\n<p>\u041b\u0438\u0434\u0435\u0440 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u043d\u0430 <code>s1-replica<\/code>:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/wr\/ot\/ps\/wrotps8fepycbp9mibbk2l4do5o.png\" data-src=\"https:\/\/habrastorage.org\/webt\/wr\/ot\/ps\/wrotps8fepycbp9mibbk2l4do5o.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c <code>s1-master<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"lua\">cartridge start -d s1-master<\/code><\/pre>\n<p>  <\/p>\n<p><code>s1-master<\/code> \u043f\u043e\u0434\u043d\u044f\u043b\u0441\u044f, \u043d\u043e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f stateful-\u0444\u0435\u0439\u043b\u043e\u0432\u0435\u0440\u0443 \u043b\u0438\u0434\u0435\u0440\u043e\u043c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f <code>s1-replica<\/code>:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/cz\/4w\/a4\/cz4wa4cxiw3xoc9wvbthdzt_dfc.png\" data-src=\"https:\/\/habrastorage.org\/webt\/cz\/4w\/a4\/cz4wa4cxiw3xoc9wvbthdzt_dfc.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0440\u043e\u043b\u0438 <code>cartridge.roles.metrics<\/code>, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 Code \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b metrics.yml \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">export:   - path: '\/metrics'     format: prometheus   - path: '\/health'     format: health<\/code><\/pre>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ff\/ud\/0v\/ffud0vznvipzhqhq8ytminevgbm.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ff\/ud\/0v\/ffud0vznvipzhqhq8ytminevgbm.png\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u043d\u0430\u0436\u043c\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 Apply, \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0443\u0437\u043b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0443 <code>localhost:8081\/metrics<\/code> \u0438 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f health-check \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>localhost:8081\/health<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430: \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0433\u043e\u0442\u043e\u0432 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043e\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e HTTP API \u0438\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430.<\/p>\n<p>  <\/p>\n<h2 id=\"zaklyuchenie\"><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/h2>\n<p>  <\/p>\n<p>\u041c\u043d\u043e\u0433\u0438\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0430\u043c \u0445\u043e\u0447\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043e\u043c \u0432\u0437\u044f\u043b \u043d\u0430 \u0441\u0435\u0431\u044f \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434. \u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e Cartridge \u2014 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043e\u043c \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 Tarantool.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043a\u0430\u043a \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0435 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Cartridge \u0438 Tarantool,<\/li>\n<li>\u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u0445,<\/li>\n<li>\u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b,<\/li>\n<li>\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0442\u0435\u0440.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>H\u0430\u0434\u0435\u044e\u0441\u044c, \u043c\u043e\u0439 \u0440\u0430\u0441\u0441\u043a\u0430\u0437 \u0431\u044b\u043b \u043f\u043e\u043b\u0435\u0437\u0435\u043d, \u0438 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Cartridge \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0411\u0443\u0434\u0443 \u0440\u0430\u0434 \u0443\u0441\u043b\u044b\u0448\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u0432\u044f\u0437\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043b\u0438 \u0443 \u0432\u0430\u0441 \u043b\u0435\u0433\u043a\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Cartridge, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e.<\/p>\n<p>  <\/p>\n<h2 id=\"chto-dalshe\"><strong>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435?<\/strong><\/h2>\n<p>  <\/p>\n<ul>\n<li>\u041f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 <a href=\"https:\/\/www.tarantool.io\/\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0430\u0439\u0442\u0435<\/a><\/li>\n<li>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 Cartridge <a href=\"https:\/\/try.tarantool.io\/\">\u0432 \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0435<\/a><\/li>\n<li>\u0417\u0430\u0434\u0430\u0439\u0442\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443 \u0432 <a href=\"https:\/\/t.me\/tarantoolru\">Telegram-\u0447\u0430\u0442\u0435<\/a><\/li>\n<li>\u0423\u0437\u043d\u0430\u0439\u0442\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u043e <a href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/465503\/\">Cartridge<\/a><\/li>\n<li>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/571936\/\">cartridge-cli<\/a><\/li>\n<li>\u041f\u0440\u0438\u043e\u0431\u0449\u0438\u0442\u0435\u0441\u044c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043e\u043f\u044b\u0442\u0443 <a href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/543086\/\">\u0434\u0435\u043f\u043b\u043e\u044f<\/a> \u0438 <a href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/548228\/\">\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438<\/a> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/li>\n<li>\u041f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u0435\u0441\u044c \u0432 <a href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/534826\/\">\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433<\/a> Tarantool<\/li>\n<li>\u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u043d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u044b\u0439 \u0442\u0435\u0441\u0442 \u043d\u0430 <a href=\"https:\/\/habr.com\/ru\/post\/517488\/\">\u041f\u0430\u043d\u0434\u043e\u0440\u0435<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/563446\/\">k6<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/588046\/\"> https:\/\/habr.com\/ru\/articles\/588046\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><img loading=\"lazy\" decoding=\"async\" height=\"1\" src=\"https:\/\/www.facebook.com\/tr?id=981564558927545&amp;ev=Habr\" style=\"display:none;\" width=\"1\"><img loading=\"lazy\" decoding=\"async\" height=\"1\" src=\"https:\/\/www.facebook.com\/tr?id=1220899431627792&amp;ev=PageView&amp;noscript=1\" style=\"display:none;\" width=\"1\"><img loading=\"lazy\" decoding=\"async\" height=\"1\" src=\"https:\/\/top-fwz1.mail.ru\/counter?id=3200881;js=na\" style=\"display:none;\" width=\"1\"><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/6n\/9w\/q1\/6n9wq1hdfugltyfwr3e3ri9kvcy.png\" data-src=\"https:\/\/habrastorage.org\/webt\/6n\/9w\/q1\/6n9wq1hdfugltyfwr3e3ri9kvcy.png\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0418\u0433\u043e\u0440\u044c \u0438 \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 Tarantool. \u041f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043c\u043d\u0435 \u0447\u0430\u0441\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0438\u043b\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f MVP. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439 \u043f\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0435\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u043e \u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0440\u0430\u0431\u043e\u0442\u0443.<\/p>\n<p>  <\/p>\n<p>\u041c\u043d\u0435 \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 SQL \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0434\u0443\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u043e\u0432. \u0425\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u0447\u0435\u043a \u043a\u043e\u0434\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. \u0412 \u0431\u044b\u0441\u0442\u0440\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043c\u043d\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 Cartridge \u2014 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u044b\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 NoSQL \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 Tarantool.<\/p>\n<p>  <\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Cartridge, \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c. \u0421\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0432\u0441\u0435\u043c, \u043a\u0442\u043e \u0443\u0441\u0442\u0430\u043b \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043b\u044e\u0434\u044f\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u044f\u0442 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e NoSQL \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044e.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-383448","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/383448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=383448"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/383448\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=383448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=383448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=383448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}