32
Senior Consulting Engineer, MongoDB Norman Graham #MongoDBWorld Retail Reference Architecture: Real-Time, Geo-Distributed Inventory

Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

  • Upload
    mongodb

  • View
    232

  • Download
    0

Embed Size (px)

DESCRIPTION

During this session we will cover the best practices for implementing a real-time inventory with MongoDB. This includes properly model quantities and stores to avoid large numbers of documents being indexed, how to efficiently use geo-indexing to find the closest store with a specific item available and how to run aggregation to gather interesting inventory stats. We will also cover operational considerations, like how to make inventory queries and updates from anywhere be low-latency and resilient to network partitions via tag-aware sharding.

Citation preview

Page 1: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Senior Consulting Engineer, MongoDB

Norman Graham

#MongoDBWorld

Retail Reference Architecture: Real-Time, Geo-Distributed Inventory

Page 2: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory

Inventory

MongoDB

External Inventory

Internal Inventory

Regional Inventory

Purchase Orders

Fulfillment

Promotions

Page 3: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Traditional Architecture

Relational DBSystem of Records

NightlyBatches

Analytics, Aggregations

,Reports

Caching Layer

Field Inventory

Internal & External

Apps

Point-in-time Loads

Page 4: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Opportunities Missed

• Can’t reliably detect availability

• Can't redirect purchasers to in-store pickup

• Can’t do intra-day replenishment

• Degraded customer experience

• Higher internal expense

Page 5: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Principles

• Single view of the inventory

• Used by most services and channels

• Read-dominated workload

• Local, real-time writes

• Bulk writes for refresh

• Geographically distributed

• Horizontally scalable

Page 6: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Requirement Challenge MongoDB

Single view of inventory

Ensure availability of inventory

information on all channels and

services

Developer-friendly, document-oriented

storage

High volume, low latency reads

Anytime, anywhere access to inventory

data without overloading the system of record

Fast, indexed readsLocal reads

Horizontal scaling

Bulk updates,intra-day deltas

Provide window-in-time consistency for

highly available services

Bulk writesFast, in-place

updatesHorizontal scaling

Rapid application development

cycles

Deliver new services rapidly to capture new opportunities

Flexible schemaRich query language

Agile-friendly iterations

Inventory – Requirements

Page 7: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Target Architecture

Relational DBSystem of Records

Analytics, Aggregations

,Reports

Field Inventory

Internal & External

Apps

Inventory

Assortments

Shipments

Audits

Products

Stores

Point-in-time Loads

NightlyRefres

h

Real-timeUpdates

Page 8: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Horizontal Scaling

Inventory – Technical Decisions

Store

Inventory

Schema

Indexing

Page 9: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Collections

Stores InventoryProducts

Audits AssortmentsShipments

Page 10: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

> db.stores.findOne(){ "_id" : ObjectId("53549fd3e4b0aaf5d6d07f35"), "className" : "catalog.Store", "storeId" : "store0", "name" : "Bessemer store", "address" : { "addr1" : "1st Main St", "city" : "Bessemer", "state" : "AL", "zip" : "12345", "country" : "US" }, "location" : [ -86.95444, 33.40178 ], ...}

Stores – Sample Document

Page 11: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Stores – Sample Queries

• Get a store by storeId

db.stores.find({ "storeId" : "store0" })

• Get a store by zip code

db.stores.find({ "address.zip" : "12345" })

Page 12: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

What’s near me?

Page 13: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Stores – Sample Geo Queries

• Get nearby stores sorted by distance

db.runCommand({

geoNear : "stores",

near : {

type : "Point",

coordinates : [-82.8006, 40.0908] },

maxDistance : 10000.0,

spherical : true

})

Page 14: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Stores – Sample Geo Queries

• Get the five nearest stores within 10 km

db.stores.find({

location : {

$near : {

$geometry : {

type : "Point",

coordinates : [-82.80, 40.09] },

$maxDistance : 10000.0 } }

}).limit(5)

Page 15: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Stores – Indices

• { "storeId" : 1 }, { "unique" : true }

• { "name" : 1 }

• { "address.zip" : 1 }

• { "location" : "2dsphere" }

Page 16: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

> db.inventory.findOne(){ "_id": "5354869f300487d20b2b011d", "storeId": "store0", "location": [-86.95444, 33.40178], "productId": "p0", "vars": [ { "sku": "sku1", "q": 14 }, { "sku": "sku3", "q": 7 }, { "sku": "sku7", "q": 32 }, { "sku": "sku14", "q": 65 }, ... ]}

Inventory – Sample Document

Page 17: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Queries

• Get all items in a store

db.inventory.find({ storeId : "store100" })

• Get quantity for an item at a store

db.inventory.find({

"storeId" : "store100",

"productId" : "p200"

})

Page 18: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Queries

• Get quantity for a sku at a store

db.inventory.find(

{

"storeId" : "store100",

"productId" : "p200",

"vars.sku" : "sku11736"

},

{ "vars.$" : 1 }

)

Page 19: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Update

• Increment / decrement inventory for an item at a store

db.inventory.update(

{

"storeId" : "store100",

"productId" : "p200",

"vars.sku" : "sku11736"

},

{ "$inc" : { "vars.$.q" : 20 } }

)

Page 20: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Aggregations

• Aggregate total quantity for a product

db.inventory.aggregate( [

{ $match : { productId : "p200" } },

{ $unwind : "$vars" },

{ $group : {

_id : "result",

count : { $sum : "$vars.q" } } } ] )

{ "_id" : "result", "count" : 101752 }

Page 21: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Aggregations

• Aggregate total quantity for a store

db.inventory.aggregate( [

{ $match : { storeId : "store100" } },

{ $unwind : "$vars" },

{ $match : { "vars.q" : { $gt : 0 } } },

{ $group : {

_id : "result",

count : { $sum : 1 } } } ] )

{ "_id" : "result", "count" : 29347 }

Page 22: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Aggregations

• Aggregate total quantity for a store

db.inventory.aggregate( [

{ $match : { storeId : "store100" } },

{ $unwind : "$vars" },

{ $group : {

_id : "result",

count : { $sum : "$vars.q" } } } ] )

{ "_id" : "result", "count" : 29347 }

Page 23: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory
Page 24: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Geo-Query

• Get inventory for an item near a point

db.runCommand( { geoNear : "inventory", near : { type : "Point", coordinates : [-82.8006, 40.0908] }, maxDistance : 10000.0, spherical : true, limit : 10, query : { "productId" : "p200", "vars.sku" : "sku11736" } } )

Page 25: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Geo-Query

• Get closest store with available sku

db.runCommand( { geoNear : "inventory", near : { type : "Point", coordinates : [-82.800672, 40.090844] }, maxDistance : 10000.0, spherical : true, limit : 1, query : { productId : "p200", vars : { $elemMatch : { sku : "sku11736", q : { $gt : 0 } } } } } )

Page 26: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Geo-Aggregation

• Get count of inventory for an item near a point

db.inventory.aggregate( [ { $geoNear: { near : { type : "Point", coordinates : [-82.800672, 40.090844] }, distanceField: "distance", maxDistance: 10000.0, spherical : true, query: { productId : "p200", vars : { $elemMatch : { sku : "sku11736", q : {$gt : 0} } } }, includeLocs: "dist.location", num: 5 } }, { $unwind: "$vars" }, { $match: { "vars.sku" : "sku11736" } }, { $group: { _id: "result", count: {$sum: "$vars.q"} } }])

Page 27: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Sample Indices

• { storeId : 1 }

• { productId : 1, storeId : 1 }

• { productId : 1, location : "2dsphere" }

• Why not "vars.sku"?– { productId : 1, storeId : 1, "vars.sku" : 1 }

Page 28: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Horizontal Scaling

Inventory – Technical Decisions

Store

Inventory

Schema

Indexing

Page 29: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

ShardEast

ShardCentr

al

ShardWest

East DC

Inventory – Sharding TopologyWest DC Central DC

LegacyInventor

y

Primary

Primary

Primary

Page 30: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Shard Key

• Choose shard key– { storeId : 1 } ?– { productId : 1, storeId : 1 } ?– { storeId : 1, productId : 1 } ?

• Set up sharding– sh.enableSharding("inventoryDB")– sh.shardCollection( "inventoryDB.inventory", { storeId : 1, productId : 1 } )

Page 31: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Inventory – Shard Tags

• Set up shard tags– sh.addShardTag("shard0000", "west")– sh.addShardTag("shard0001", "central")– sh.addShardTag("shard0002", "east")

• Set up tag ranges– sh.addTagRange("inventoryDB.inventory", { storeId : 0 }, { storeId : 100}, "west" )– sh.addTagRange("inventoryDB.inventory", { storeId : 100 }, { storeId : 200 }, "central" )– sh.addTagRange("inventoryDB.inventory", { storeId : 200 }, { storeId : 300 }, "east" )

Page 32: Retail Reference Architecture Part 2: Real-Time, Geo Distributed Inventory

Senior Consulting Engineer, MongoDB

Norman Graham

#MongoDBWorld

Thank You