A redis module that provides a type for inventory deduction in flash sales

Overview

Inventory

LANGUAGE LICENSE GitHub code size in bytes dependency status GitHub Workflow Status

This is a redis module that provides a type for inventory deduction in flash sales.

#[repr(C)]
struct Inventory {
    total: u32,
    current: u32,
}

use std::mem::size_of;
assert_eq!(size_of::
   (), 
   size_of
   ::<
   u64>());
  

Commands

  • inv.set key total: Set the inventory value of a key.
  • inv.setnx key total: Set the inventory value of a key, only if the key does not exist.
  • inv.get key: Get the inventory of a key, including total and current.
  • inv.ddct key [amount(default=1)]: Check and deduct inventory.
  • inv.incr key amount: Increase total and current.
  • inv.return key amount: Increase current.
  • inv.del key: Delete an inventory.

Build

Make sure you have Rust installed: https://www.rust-lang.org/tools/install

Then, build as usual:

cargo build --release

When running the tests, you need to explicitly specify the test feature to disable use of the Redis memory allocator when testing:

cargo test --features test

If you forget to do this, you'll see an error mentioning signal: 4, SIGILL: illegal instruction.

Run

Linux

redis-server --loadmodule ./target/release/libinventory.so

Mac OS

redis-server --loadmodule ./target/release/libinventory.dylib

Benchmark

The following benchmark results are from my new Mac (special thanks to my girlfriend), using the M1 chip.

PING

Script:

$ redis-benchmark -n 10000000 ping

Output:

  throughput summary: 206752.53 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        0.138     0.048     0.135     0.183     0.279     2.351
details
====== ping ======                                                     
  10000000 requests completed in 48.37 seconds
  50 parallel clients
  14 bytes payload
  keep alive: 1
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no

Latency by percentile distribution: 0.000% <= 0.055 milliseconds (cumulative count 2) 50.000% <= 0.135 milliseconds (cumulative count 5688196) 75.000% <= 0.151 milliseconds (cumulative count 8010099) 87.500% <= 0.167 milliseconds (cumulative count 9159920) 93.750% <= 0.175 milliseconds (cumulative count 9433296) 96.875% <= 0.199 milliseconds (cumulative count 9716460) 98.438% <= 0.255 milliseconds (cumulative count 9848161) 99.219% <= 0.287 milliseconds (cumulative count 9935164) 99.609% <= 0.311 milliseconds (cumulative count 9966971) 99.805% <= 0.335 milliseconds (cumulative count 9981121) 99.902% <= 0.375 milliseconds (cumulative count 9991420) 99.951% <= 0.415 milliseconds (cumulative count 9995520) 99.976% <= 0.471 milliseconds (cumulative count 9997690) 99.988% <= 0.551 milliseconds (cumulative count 9998801) 99.994% <= 0.983 milliseconds (cumulative count 9999391) 99.997% <= 1.815 milliseconds (cumulative count 9999717) 99.998% <= 1.879 milliseconds (cumulative count 9999858) 99.999% <= 1.927 milliseconds (cumulative count 9999928) 100.000% <= 2.015 milliseconds (cumulative count 9999963) 100.000% <= 2.135 milliseconds (cumulative count 9999981) 100.000% <= 2.199 milliseconds (cumulative count 9999991) 100.000% <= 2.247 milliseconds (cumulative count 9999996) 100.000% <= 2.311 milliseconds (cumulative count 9999998) 100.000% <= 2.319 milliseconds (cumulative count 9999999) 100.000% <= 2.351 milliseconds (cumulative count 10000000) 100.000% <= 2.351 milliseconds (cumulative count 10000000)

Cumulative distribution of latencies: 1.770% <= 0.103 milliseconds (cumulative count 177015) 97.412% <= 0.207 milliseconds (cumulative count 9741165) 99.593% <= 0.303 milliseconds (cumulative count 9959251) 99.950% <= 0.407 milliseconds (cumulative count 9994962) 99.983% <= 0.503 milliseconds (cumulative count 9998252) 99.990% <= 0.607 milliseconds (cumulative count 9999005) 99.991% <= 0.703 milliseconds (cumulative count 9999129) 99.993% <= 0.807 milliseconds (cumulative count 9999279) 99.994% <= 0.903 milliseconds (cumulative count 9999352) 99.994% <= 1.007 milliseconds (cumulative count 9999404) 99.994% <= 1.103 milliseconds (cumulative count 9999444) 99.995% <= 1.207 milliseconds (cumulative count 9999463) 99.995% <= 1.303 milliseconds (cumulative count 9999468) 99.995% <= 1.407 milliseconds (cumulative count 9999471) 99.995% <= 1.503 milliseconds (cumulative count 9999482) 99.995% <= 1.607 milliseconds (cumulative count 9999521) 99.995% <= 1.703 milliseconds (cumulative count 9999547) 99.997% <= 1.807 milliseconds (cumulative count 9999691) 99.999% <= 1.903 milliseconds (cumulative count 9999896) 100.000% <= 2.007 milliseconds (cumulative count 9999961) 100.000% <= 2.103 milliseconds (cumulative count 9999979) 100.000% <= 3.103 milliseconds (cumulative count 10000000)

Summary: throughput summary: 206752.53 requests per second latency summary (msec): avg min p50 p95 p99 max 0.138 0.048 0.135 0.183 0.279 2.351

Lua script

Initialization:

k then redis.call("HINCRBY", KEYS[1], "current", -k); return k; end;return 0'">
redis> hmset bench_lua total 10000000 current 10000000
redis> script load 'local counts = redis.call("HMGET", KEYS[1], "total", "current");local total = tonumber(counts[1]);local current = tonumber(counts[2]);local k = tonumber(ARGV[1]); if current > k then redis.call("HINCRBY", KEYS[1], "current", -k); return k; end;return 0'

Script:

$ redis-benchmark -n 10000000 evalsha [scriptsha] 1 bench_lua 1 1

Output:

  throughput summary: 184145.11 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        0.224     0.080     0.223     0.327     0.463     2.479
details
====== evalsha 8d288ce6effb69b0664723d46a0051772621537a 1 bench_lua 1 1 ======
  10000000 requests completed in 54.31 seconds
  50 parallel clients
  100 bytes payload
  keep alive: 1
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no

Latency by percentile distribution: 0.000% <= 0.087 milliseconds (cumulative count 518) 50.000% <= 0.223 milliseconds (cumulative count 5542612) 75.000% <= 0.255 milliseconds (cumulative count 7561675) 87.500% <= 0.295 milliseconds (cumulative count 8933778) 93.750% <= 0.319 milliseconds (cumulative count 9435941) 96.875% <= 0.351 milliseconds (cumulative count 9705820) 98.438% <= 0.423 milliseconds (cumulative count 9852368) 99.219% <= 0.487 milliseconds (cumulative count 9927421) 99.609% <= 0.535 milliseconds (cumulative count 9966579) 99.805% <= 0.559 milliseconds (cumulative count 9981256) 99.902% <= 0.583 milliseconds (cumulative count 9990980) 99.951% <= 0.607 milliseconds (cumulative count 9995904) 99.976% <= 0.631 milliseconds (cumulative count 9997987) 99.988% <= 0.655 milliseconds (cumulative count 9998827) 99.994% <= 1.023 milliseconds (cumulative count 9999393) 99.997% <= 1.671 milliseconds (cumulative count 9999701) 99.998% <= 1.807 milliseconds (cumulative count 9999850) 99.999% <= 1.943 milliseconds (cumulative count 9999924) 100.000% <= 2.063 milliseconds (cumulative count 9999965) 100.000% <= 2.215 milliseconds (cumulative count 9999981) 100.000% <= 2.343 milliseconds (cumulative count 9999992) 100.000% <= 2.391 milliseconds (cumulative count 9999996) 100.000% <= 2.431 milliseconds (cumulative count 9999998) 100.000% <= 2.447 milliseconds (cumulative count 9999999) 100.000% <= 2.479 milliseconds (cumulative count 10000000) 100.000% <= 2.479 milliseconds (cumulative count 10000000)

Cumulative distribution of latencies: 0.321% <= 0.103 milliseconds (cumulative count 32072) 43.738% <= 0.207 milliseconds (cumulative count 4373816) 91.282% <= 0.303 milliseconds (cumulative count 9128228) 98.285% <= 0.407 milliseconds (cumulative count 9828487) 99.418% <= 0.503 milliseconds (cumulative count 9941792) 99.959% <= 0.607 milliseconds (cumulative count 9995904) 99.992% <= 0.703 milliseconds (cumulative count 9999245) 99.993% <= 0.807 milliseconds (cumulative count 9999315) 99.993% <= 0.903 milliseconds (cumulative count 9999340) 99.994% <= 1.007 milliseconds (cumulative count 9999372) 99.994% <= 1.103 milliseconds (cumulative count 9999420) 99.994% <= 1.207 milliseconds (cumulative count 9999449) 99.995% <= 1.303 milliseconds (cumulative count 9999479) 99.995% <= 1.407 milliseconds (cumulative count 9999524) 99.996% <= 1.503 milliseconds (cumulative count 9999564) 99.996% <= 1.607 milliseconds (cumulative count 9999615) 99.997% <= 1.703 milliseconds (cumulative count 9999746) 99.999% <= 1.807 milliseconds (cumulative count 9999850) 99.999% <= 1.903 milliseconds (cumulative count 9999909) 99.999% <= 2.007 milliseconds (cumulative count 9999948) 100.000% <= 2.103 milliseconds (cumulative count 9999971) 100.000% <= 3.103 milliseconds (cumulative count 10000000)

Summary: throughput summary: 184145.11 requests per second latency summary (msec): avg min p50 p95 p99 max 0.224 0.080 0.223 0.327 0.463 2.479

Inventory module

Initialization:

redis> inv.set bench_inv 10000000

Script:

$ redis-benchmark -n 10000000 inv.ddct bench_inv

Output:

  throughput summary: 200553.53 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        0.155     0.056     0.143     0.247     0.423     2.583
details
====== inv.ddct bench_inv ======
  10000000 requests completed in 49.86 seconds
  50 parallel clients
  33 bytes payload
  keep alive: 1
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no

Latency by percentile distribution: 0.000% <= 0.063 milliseconds (cumulative count 1) 50.000% <= 0.143 milliseconds (cumulative count 5174947) 75.000% <= 0.167 milliseconds (cumulative count 8039536) 87.500% <= 0.183 milliseconds (cumulative count 8880992) 93.750% <= 0.215 milliseconds (cumulative count 9392336) 96.875% <= 0.295 milliseconds (cumulative count 9694479) 98.438% <= 0.375 milliseconds (cumulative count 9845786) 99.219% <= 0.439 milliseconds (cumulative count 9923638) 99.609% <= 0.495 milliseconds (cumulative count 9964499) 99.805% <= 0.535 milliseconds (cumulative count 9983634) 99.902% <= 0.559 milliseconds (cumulative count 9991677) 99.951% <= 0.583 milliseconds (cumulative count 9996100) 99.976% <= 0.607 milliseconds (cumulative count 9997969) 99.988% <= 0.647 milliseconds (cumulative count 9998834) 99.994% <= 1.079 milliseconds (cumulative count 9999391) 99.997% <= 1.823 milliseconds (cumulative count 9999696) 99.998% <= 2.143 milliseconds (cumulative count 9999849) 99.999% <= 2.247 milliseconds (cumulative count 9999927) 100.000% <= 2.407 milliseconds (cumulative count 9999964) 100.000% <= 2.463 milliseconds (cumulative count 9999983) 100.000% <= 2.495 milliseconds (cumulative count 9999995) 100.000% <= 2.511 milliseconds (cumulative count 9999996) 100.000% <= 2.575 milliseconds (cumulative count 9999998) 100.000% <= 2.583 milliseconds (cumulative count 10000000) 100.000% <= 2.583 milliseconds (cumulative count 10000000)

Cumulative distribution of latencies: 0.849% <= 0.103 milliseconds (cumulative count 84944) 93.381% <= 0.207 milliseconds (cumulative count 9338065) 97.173% <= 0.303 milliseconds (cumulative count 9717262) 98.887% <= 0.407 milliseconds (cumulative count 9888745) 99.688% <= 0.503 milliseconds (cumulative count 9968847) 99.980% <= 0.607 milliseconds (cumulative count 9997969) 99.990% <= 0.703 milliseconds (cumulative count 9998960) 99.991% <= 0.807 milliseconds (cumulative count 9999099) 99.992% <= 0.903 milliseconds (cumulative count 9999223) 99.993% <= 1.007 milliseconds (cumulative count 9999326) 99.994% <= 1.103 milliseconds (cumulative count 9999416) 99.995% <= 1.207 milliseconds (cumulative count 9999468) 99.995% <= 1.303 milliseconds (cumulative count 9999484) 99.995% <= 1.407 milliseconds (cumulative count 9999503) 99.995% <= 1.503 milliseconds (cumulative count 9999526) 99.996% <= 1.607 milliseconds (cumulative count 9999600) 99.996% <= 1.703 milliseconds (cumulative count 9999630) 99.997% <= 1.807 milliseconds (cumulative count 9999677) 99.997% <= 1.903 milliseconds (cumulative count 9999747) 99.998% <= 2.007 milliseconds (cumulative count 9999820) 99.998% <= 2.103 milliseconds (cumulative count 9999841) 100.000% <= 3.103 milliseconds (cumulative count 10000000)

Summary: throughput summary: 200553.53 requests per second latency summary (msec): avg min p50 p95 p99 max 0.155 0.056 0.143 0.247 0.423 2.583

Conclusion

The performance of this module is only slightly better than using lua scripts. Maybe the redis module is only suitable for dealing with more complex in-memory data structures, especially those that are more efficient after deserialization, such as JSON.

License

MIT

You might also like...
A port of `java.util.*SummaryStatistics` as a Redis Module

RedisNumbersStats RedisNumbersStats is a Redis module that implements a Redis version of the Java Util *SummaryStatistics classes, such as DoubleSumma

RedisJSON - a JSON data type for Redis

RedisJSON RedisJSON is a Redis module that implements ECMA-404 The JSON Data Interchange Standard as a native data type. It allows storing, updating a

A Flash Player emulator written in Rust
A Flash Player emulator written in Rust

website | demo | nightly builds | wiki Ruffle Ruffle is an Adobe Flash Player emulator written in the Rust programming language. Ruffle targets both t

A (flash) message framework for actix-web. A port to Rust of Django's message framework.

actix-web-flash-messages Flash messages for actix-web Web applications sometimes need to show a one-time notification to the user - e.g. an error mess

TinyUF2 flash unlocker for STM32F411 (easily adaptable to other STM32F4xx)

TinyUF2 flash unlocker for STM32F411 (easily adaptable to other STM32F4xx) This small program is meant to unlock the first 2 (=32kb) flash sectors tha

Key-value store for embedded systems, for raw NOR flash, using an LSM-Tree.

ekv Key-value store for embedded systems, for raw NOR flash, using an LSM-Tree. Features None yet TODO Everything Minimum supported Rust version (MSRV

A template for writing CMSIS-Pack flash algorithms in Rust

Flash Algorithm Template This is a flash algorithm template for writing CMSIS-Pack flash algorithms in Rust. It can be used to generate new flash algo

This PAM module provides ssh-agent based authentication

PAM-RSSH This PAM module provides ssh-agent based authentication. The primary design goal is to avoid typing password when you sudo on remote servers.

This library implements a type macro for a zero-sized type that is Serde deserializable only from one specific value.

Monostate This library implements a type macro for a zero-sized type that is Serde deserializable only from one specific value. [dependencies] monosta

Type erased vector. All elements have the same type.

Type erased vector. All elements have the same type. Designed to be type-erased as far as possible - most of the operations does not know about concre

Build database expression type checker and vectorized runtime executor in type-safe Rust

Typed Type Exercise in Rust Build database expression type checker and vectorized runtime executor in type-safe Rust. This project is highly inspired

Translate C++/Rust type into C type with the same memory layout

clayout, translate C++/Rust type into C type with the same memory layout. Generally, clayout is used together with bpftrace. clayout is developed on d

A crate that allows you to mostly-safely cast one type into another type.

A crate that allows you to mostly-safely cast one type into another type. This is mostly useful for generic functions, e.g. pub fn fooS(s: S) {

This crate provides a convenient macro that allows you to generate type wrappers that promise to always uphold arbitrary invariants that you specified.

prae This crate provides a convenient macro that allows you to generate type wrappers that promise to always uphold arbitrary invariants that you spec

Redis re-implemented in Rust.

rsedis Redis re-implemented in Rust. Why? To learn Rust. Use Cases rsedis does not rely on UNIX-specific features. Windows users can run it as a repla

Redis library for rust

redis-rs Redis-rs is a high level redis library for Rust. It provides convenient access to all Redis functionality through a very flexible but low-lev

RedisLess is a fast, lightweight, embedded and scalable in-memory Key/Value store library compatible with the Redis API.

RedisLess is a fast, lightweight, embedded and scalable in-memory Key/Value store library compatible with the Redis API.

A high level async Redis client for Rust built on Tokio and Futures.

A high level async Redis client for Rust built on Tokio and Futures.

Mordern Redis Cluster solution for easy operation.

Mordern Redis Cluster solution for easy operation.

Owner
GengTeng
GengTeng
Some collections to store a fixed number of elements of a specific type.

This repo provide some useful data-structures, such as: Array, HashMap, HashSet, BTreeMap, BTreeSet, etc... That lives on the stack. It's a good choic

null 0 Nov 2, 2022
Serializable map of any type.

??️ type_reg Serializable map of any type. This library provides a map that can store any serializable type, and retrieve it as the strong type. Seria

Azriel Hoh 3 Dec 26, 2022
A Redis module that provides rate limiting in Redis as a single command.

redis-cell A Redis module that provides rate limiting in Redis as a single command. Implements the fairly sophisticated generic cell rate algorithm (G

Brandur Leach 1.1k Jan 6, 2023
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
Validity is a next-generation, deduction-based language for formally verified, context-aware, autonomous & reactive smart contracts.

Validity Language Validity is a next-generation, deduction-based language for formally verified, context-aware, autonomous & reactive smart contracts.

Tempest Labs 4 Nov 11, 2022
An handy tool that is intended to help your inventory cleanup or dump.

NeosVR Inventory Management Notes to foreign users This readme is written in Japanese. Please use external tool to translate this document into your l

Kisaragi 16 Dec 15, 2022
Generic inventory system built in pure rust.

game_inventory A framework for generalizing inventory logic and abstracting it away from item data in your specific game. See more examples and specif

null 7 Jul 30, 2022
This is a validator of Fitch style natural deduction proofs.

What is this? This is a formal proof validator, which assesses the correctness of Fitch-style natural deduction proofs ("Fitch proofs"). The tool also

null 3 Apr 10, 2024
Redis Tree(Ploytree) Structure Module

RedisTree is a Redis module that implements Polytree as a native data type. It allows creating,locating,pushing and detaching tree from Redi

Bonsai 63 Dec 25, 2022
[POC] Redis Module for TiKV

RedisTikvPoc [POC] Redis Module for TiKV This is a POC repository. This Redis Module will add branch new Redis commands to operate TiKV data. After bu

Rain Li 6 Jun 25, 2022