SlideShare a Scribd company logo
Шардинг заказов
корзины каталога
Петр Трофимов
600 разделов
800 000 товаров
1000+ магазинов
и почти 5 000 000позиций
Cart.api
app1
app2
app3
app4
...
db1
db2
db3
db4
...
order
order1
order2
orderN
credentials.api
catalog.api
shop.api
geo.api
host1
db1
table1
Споты
spot1 spot2
table2
spot3
db2
spot4
spot5
host2
spot6
spot7
hostN
Карта спотов
start_id finish_id connection_name database spot_prefix
1 1000000 host100 cart10 chunk1_
1000001 2000000 host101 cart11 chunk2_
... ... ... ... ...
10000001 0 host110 cart120 chunk10_
abstract class Model extends EloquentModel
{
protected $spotIdKey;
public function spot()
{
return $this->spot ? : Map::spot($this->getAttributeFromArray($this->spotIdKey));
}
public function getConnection()
{
return $this->spotConnection($this->spot());
}
public function spotConnection(Spot $spot)
{
$configKey = "database.connections.{$spot->connectionName}";
if (!config($configKey)) {
app('config')->set($configKey, $this->spotConfig($spot));
}
return static::resolveConnection($spot->connectionName);
}
public function getTable()
{
return $this->spot()->database . '.' . $this->spot()->spotPrefix . parent::getTable();
}
}
Как искать в спотах?
spot1 spot2 spot3 spot4 spotN
client
SELECT * FROM orders WHERE shop_id = ?
Превью
spotN spot2 spotN
client
preview
preview
WRITE READ
client
spot1
preview
spot3
class PreviewUpdater
{
public function created(Order $order)
{
OrderPreview::create([
'id' => $order->id,
'user_id' => $order->user_id,
'status' => $order->status,
// ...
]);
}
public function updated(Order $order)
{
/** @var OrderPreview $orderPreview */
$orderPreview = OrderPreview::find($order->id);
$orderPreview->user_id = $order->user_id;
$orderPreview->status = $order->status;
// ...
$orderPreview->save();
}
public function deleted(Order $order)
{
OrderPreview::destroy($order->id);
}
}
abstract class Model extends EloquentModel
{
public static function find($id, $columns = ['*'])
{
if (is_array($id)) {
return static::findMany($id, $columns);
}
return static::spotQuery(Map::spot($id))->find($id, $columns);
}
public static function spotQuery(Spot $spot)
{
$instance = new static;
$instance->spot = $spot;
$connection = $instance->spotConnection($spot);
$builder = $instance->newEloquentBuilder(
new QueryBuilder($connection, $connection->getQueryGrammar(), $connection->getPostProcessor())
);
return $builder->setModel($instance);
}
// ...
}
$order = OrderPreview::orderQuery()->whereOrderKey($orderId)->first();
class OrderPreview extends Model
{
public static function orderQuery()
{
$instance = new static;
return (new QueryBuilder($instance->newBaseQueryBuilder(), new Order))->setModel($instance);
}
}
class QueryBuilder extends Builder
{
/** @var Model */
private $spotted;
private $with = [];
public function getModels($columns = ['*'])
{
return $this->spotted->findMany(array_pluck(parent::getModels($columns), 'id'), $columns,
$this->with)->all();
}
}
Запросы через превью
abstract class Model extends EloquentModel
{
public function hasMany($related, $foreignKey = null, $localKey = null)
{
//...
$instance = new $related;
$instance->spot = $this->spot();
return new HasMany(/*...*/, $instance->getTable() . '.' . $foreignKey);
}
}
Поддержка relations
Scenario: Spots with different databases
Given spots map contains spots:
| start_id | finish_id | connection_name | database | spot_prefix |
| 1 | 1 | catalog_cart | <test_db> | |
| 2 | 2 | catalog_cart_spot2 | <test_db>_spot2 | |
# ...
When I send POST request to "/orders"
Then request expectations should be met
And log file should be empty
And response status code should be 201
And SQL query "select * from <test_db>.orders" result should be like:
| id | user_id | shop_id | status | delivery_city | delivery_address | comment |
| 1 | 1 | 1 | 0 | Минск | пр-т Дзержинского, 5 | comment1 |
# ...
Behat-сценарии для спотов
Спасибо за внимание. Вопросы?
● https://catalog.onliner.by/
● https://cart.onliner.by/
● http://php.spb.ru/ms/description.html
● https://engineering.instagram.com/sharding-ids-at-
instagram-1cf5a71e5a5c
Генерация ID
● Auto-increment ID (1, 2, 3, …)
○ Закрыть информацию
○ Шардинг
● Hashids (3jR-OCl4rG0)
○ Number vector
○ Недостаточно безопасные
● UUID (550e8400-e29b-41d4-a716-446655440000)
○ Нечитаемые
● ID sequence
○ Читаемый набор символов (без i и 1)
○ Единый центр выдачи идентификаторов
○ Механизм отслеживания коллизий
$this->sequence = $connection->table('order_id_sequence');
// ...
for ($i = 1; $i <= config('order.key.collisions.limit'); $i++) {
try {
$order->key = $this->generateOrderKey();
$order->id = $this->sequence->insertGetId(['order_key' => $order->key]);
return;
} catch (QueryException $ex) {
if ($ex->getCode() != 23000) { // Integrity constraint violation
throw $ex;
}
}
if ($i == config('order.key.collisions.warning')) {
(new OnlinerLogger)->warning(
"cart-api: $i collisions occurred, think about increasing of order key length"
);
}
}
throw new RuntimeException(
"Failed to generate key for order from user {$order->user_id} to shop {$order->user_id}"
);
class Order extends SpotsModel
{
public $incrementing = false;
protected $spotIdKey = 'id';
protected $table = 'orders';
public function statusLogEntries()
{
return $this->hasMany(OrderStatusLogEntry::class);
}
public function save(array $options = [])
{
if (!$this->exists) {
// ...
app(IdGenerator::class)->generate($this);
}
return parent::save($options);
}
protected static function boot()
{
parent::boot();
// ...
static::observe(PreviewUpdater::class);
}
}

More Related Content

Similar to Шардинг заказов корзины каталога Onliner.by

Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the code
Wim Godden
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the code
Wim Godden
 
Beyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeBeyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the code
Wim Godden
 
Apache Spark in your likeness - low and high level customization
Apache Spark in your likeness - low and high level customizationApache Spark in your likeness - low and high level customization
Apache Spark in your likeness - low and high level customization
Bartosz Konieczny
 
Reverse Engineering iOS apps
Reverse Engineering iOS appsReverse Engineering iOS apps
Reverse Engineering iOS apps
Max Bazaliy
 
Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++
corehard_by
 
performance vamos dormir mais?
performance vamos dormir mais?performance vamos dormir mais?
performance vamos dormir mais?
tdc-globalcode
 
New Framework - ORM
New Framework - ORMNew Framework - ORM
New Framework - ORM
Odoo
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
Pierre MARTIN
 
Distributed Queries in IDS: New features.
Distributed Queries in IDS: New features.Distributed Queries in IDS: New features.
Distributed Queries in IDS: New features.
Keshav Murthy
 
19 programming sq lite on windows phone 8.1
19   programming sq lite on windows phone 8.119   programming sq lite on windows phone 8.1
19 programming sq lite on windows phone 8.1
WindowsPhoneRocks
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Compare mysql5.1.50 mysql5.5.8
Compare mysql5.1.50 mysql5.5.8Compare mysql5.1.50 mysql5.5.8
Compare mysql5.1.50 mysql5.5.8
Philip Zhong
 
Write Faster SQL with Trino.pdf
Write Faster SQL with Trino.pdfWrite Faster SQL with Trino.pdf
Write Faster SQL with Trino.pdf
Eric Xiao
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and EvaluationWebinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
MongoDB
 
Relational Database Access with Python ‘sans’ ORM
Relational Database Access with Python ‘sans’ ORM  Relational Database Access with Python ‘sans’ ORM
Relational Database Access with Python ‘sans’ ORM
Mark Rees
 
PyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialPyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorial
jbellis
 
Introducere in web
Introducere in webIntroducere in web
Introducere in web
Alex Eftimie
 
SequoiaDB Distributed Relational Database
SequoiaDB Distributed Relational DatabaseSequoiaDB Distributed Relational Database
SequoiaDB Distributed Relational Database
wangzhonnew
 
Introduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-finalIntroduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-final
M Malai
 

Similar to Шардинг заказов корзины каталога Onliner.by (20)

Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the code
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the code
 
Beyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeBeyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the code
 
Apache Spark in your likeness - low and high level customization
Apache Spark in your likeness - low and high level customizationApache Spark in your likeness - low and high level customization
Apache Spark in your likeness - low and high level customization
 
Reverse Engineering iOS apps
Reverse Engineering iOS appsReverse Engineering iOS apps
Reverse Engineering iOS apps
 
Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++
 
performance vamos dormir mais?
performance vamos dormir mais?performance vamos dormir mais?
performance vamos dormir mais?
 
New Framework - ORM
New Framework - ORMNew Framework - ORM
New Framework - ORM
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
Distributed Queries in IDS: New features.
Distributed Queries in IDS: New features.Distributed Queries in IDS: New features.
Distributed Queries in IDS: New features.
 
19 programming sq lite on windows phone 8.1
19   programming sq lite on windows phone 8.119   programming sq lite on windows phone 8.1
19 programming sq lite on windows phone 8.1
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Compare mysql5.1.50 mysql5.5.8
Compare mysql5.1.50 mysql5.5.8Compare mysql5.1.50 mysql5.5.8
Compare mysql5.1.50 mysql5.5.8
 
Write Faster SQL with Trino.pdf
Write Faster SQL with Trino.pdfWrite Faster SQL with Trino.pdf
Write Faster SQL with Trino.pdf
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and EvaluationWebinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
 
Relational Database Access with Python ‘sans’ ORM
Relational Database Access with Python ‘sans’ ORM  Relational Database Access with Python ‘sans’ ORM
Relational Database Access with Python ‘sans’ ORM
 
PyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialPyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorial
 
Introducere in web
Introducere in webIntroducere in web
Introducere in web
 
SequoiaDB Distributed Relational Database
SequoiaDB Distributed Relational DatabaseSequoiaDB Distributed Relational Database
SequoiaDB Distributed Relational Database
 
Introduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-finalIntroduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-final
 

Recently uploaded

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
nkrafacyberclub
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
Pierluigi Pugliese
 

Recently uploaded (20)

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
 

Шардинг заказов корзины каталога Onliner.by

  • 2.
  • 3. 600 разделов 800 000 товаров 1000+ магазинов и почти 5 000 000позиций
  • 6. Карта спотов start_id finish_id connection_name database spot_prefix 1 1000000 host100 cart10 chunk1_ 1000001 2000000 host101 cart11 chunk2_ ... ... ... ... ... 10000001 0 host110 cart120 chunk10_
  • 7. abstract class Model extends EloquentModel { protected $spotIdKey; public function spot() { return $this->spot ? : Map::spot($this->getAttributeFromArray($this->spotIdKey)); } public function getConnection() { return $this->spotConnection($this->spot()); } public function spotConnection(Spot $spot) { $configKey = "database.connections.{$spot->connectionName}"; if (!config($configKey)) { app('config')->set($configKey, $this->spotConfig($spot)); } return static::resolveConnection($spot->connectionName); } public function getTable() { return $this->spot()->database . '.' . $this->spot()->spotPrefix . parent::getTable(); } }
  • 8. Как искать в спотах? spot1 spot2 spot3 spot4 spotN client SELECT * FROM orders WHERE shop_id = ?
  • 10. class PreviewUpdater { public function created(Order $order) { OrderPreview::create([ 'id' => $order->id, 'user_id' => $order->user_id, 'status' => $order->status, // ... ]); } public function updated(Order $order) { /** @var OrderPreview $orderPreview */ $orderPreview = OrderPreview::find($order->id); $orderPreview->user_id = $order->user_id; $orderPreview->status = $order->status; // ... $orderPreview->save(); } public function deleted(Order $order) { OrderPreview::destroy($order->id); } }
  • 11. abstract class Model extends EloquentModel { public static function find($id, $columns = ['*']) { if (is_array($id)) { return static::findMany($id, $columns); } return static::spotQuery(Map::spot($id))->find($id, $columns); } public static function spotQuery(Spot $spot) { $instance = new static; $instance->spot = $spot; $connection = $instance->spotConnection($spot); $builder = $instance->newEloquentBuilder( new QueryBuilder($connection, $connection->getQueryGrammar(), $connection->getPostProcessor()) ); return $builder->setModel($instance); } // ... }
  • 12. $order = OrderPreview::orderQuery()->whereOrderKey($orderId)->first(); class OrderPreview extends Model { public static function orderQuery() { $instance = new static; return (new QueryBuilder($instance->newBaseQueryBuilder(), new Order))->setModel($instance); } } class QueryBuilder extends Builder { /** @var Model */ private $spotted; private $with = []; public function getModels($columns = ['*']) { return $this->spotted->findMany(array_pluck(parent::getModels($columns), 'id'), $columns, $this->with)->all(); } } Запросы через превью
  • 13. abstract class Model extends EloquentModel { public function hasMany($related, $foreignKey = null, $localKey = null) { //... $instance = new $related; $instance->spot = $this->spot(); return new HasMany(/*...*/, $instance->getTable() . '.' . $foreignKey); } } Поддержка relations
  • 14. Scenario: Spots with different databases Given spots map contains spots: | start_id | finish_id | connection_name | database | spot_prefix | | 1 | 1 | catalog_cart | <test_db> | | | 2 | 2 | catalog_cart_spot2 | <test_db>_spot2 | | # ... When I send POST request to "/orders" Then request expectations should be met And log file should be empty And response status code should be 201 And SQL query "select * from <test_db>.orders" result should be like: | id | user_id | shop_id | status | delivery_city | delivery_address | comment | | 1 | 1 | 1 | 0 | Минск | пр-т Дзержинского, 5 | comment1 | # ... Behat-сценарии для спотов
  • 15. Спасибо за внимание. Вопросы? ● https://catalog.onliner.by/ ● https://cart.onliner.by/ ● http://php.spb.ru/ms/description.html ● https://engineering.instagram.com/sharding-ids-at- instagram-1cf5a71e5a5c
  • 16. Генерация ID ● Auto-increment ID (1, 2, 3, …) ○ Закрыть информацию ○ Шардинг ● Hashids (3jR-OCl4rG0) ○ Number vector ○ Недостаточно безопасные ● UUID (550e8400-e29b-41d4-a716-446655440000) ○ Нечитаемые ● ID sequence ○ Читаемый набор символов (без i и 1) ○ Единый центр выдачи идентификаторов ○ Механизм отслеживания коллизий
  • 17. $this->sequence = $connection->table('order_id_sequence'); // ... for ($i = 1; $i <= config('order.key.collisions.limit'); $i++) { try { $order->key = $this->generateOrderKey(); $order->id = $this->sequence->insertGetId(['order_key' => $order->key]); return; } catch (QueryException $ex) { if ($ex->getCode() != 23000) { // Integrity constraint violation throw $ex; } } if ($i == config('order.key.collisions.warning')) { (new OnlinerLogger)->warning( "cart-api: $i collisions occurred, think about increasing of order key length" ); } } throw new RuntimeException( "Failed to generate key for order from user {$order->user_id} to shop {$order->user_id}" );
  • 18. class Order extends SpotsModel { public $incrementing = false; protected $spotIdKey = 'id'; protected $table = 'orders'; public function statusLogEntries() { return $this->hasMany(OrderStatusLogEntry::class); } public function save(array $options = []) { if (!$this->exists) { // ... app(IdGenerator::class)->generate($this); } return parent::save($options); } protected static function boot() { parent::boot(); // ... static::observe(PreviewUpdater::class); } }

Editor's Notes

  1. Привет, петр трофимов, спасибо, несмотря на дедлайны, чтото полезное, вопросы в конце 1 мин
  2. Кто заказывает товары через корзину в каталоге? Поднять Кто нет? А кто будет теперь? (из названия хехе) До этого - телефоны, але?, рога и копыта, нету да, положить денег на телефон Октябрь 2015 - декабрь 2015 Все проще, нажимаем, превращается вот в такую Конечно не все так просто, там еще эту и эту нажать Уведомление 3 мин
  3. Какова специфика каталога онлайнер? 800 тысяч, 600, 1000, 5 млн Заказов больше, чем в одиночном магазине - много данных Много разнородных магазинов - частые обновления, получить актуальные данные Частые изменения прайсов - фиксация данных, много данных Состав может меняться - нужно фиксировать, снэпшоты, много данных Заказы храним очень долго, пока не удалят - много данных, чем старше тем ненужнее Можно ли сохранить в одной таблице? Приватные сообщения Шардинг в начале, потом очень сложно Что происходит после нажатия кнопки отправить заказ? 4 мин
  4. Разбивка по магазину, JWT токен, микросервисы, внутренние запросы, выбор хранилища
  5. Кусочек данных, перенос между серверами, балансировка, закрытие открытие Что из себя представляет карта?
  6. Просто таблица, неравномерные диапазоны, хост, база, префикс, открытые диапазоны Все ходят в эту таблицу? Нет, офлайн сброс
  7. Абстрактный, спот айди, Выбор спота, переопределить системный метод подключения, Сет подключения в конфиг, выбор таблицы - переопределить
  8. Спотов много, делать запрос к каждому?
  9. Запись и туда и туда, чтение через превью, репликация ()
  10. Листенер, создание, обновление, удаление
  11. Метод поиска, выбор подключения
  12. Что такое релейшнс, связанные таблицы, ограничение - один спот, джойны
  13. Коллизии - 5 и 100, уникальный индекс, Кто знает что такое Hashids? Реакция - ты крутой
  14. Сиквенс обычная таблица, несколько попыток перед исключением, Вставка в уникальный индекс, ловим исключение, Ворнинг
  15. Спец родительский класс, отключаем автоинкремент, Указываем спотируемое поле, таблица обычное имя, Релейшны можно, генерация айди, Превью апдейтер, сколько нужно