同時在庫削減redis vs mysql
ビジネス
商品に在庫がある場合、10000で商品を1つ買うごとに在庫が1つ減ります.
在庫削減はmysqlで実現できます.
redisを使用して、次のように実装することもできます.
このようなシーンに直面して
在庫を更新してredisとmysqlを比較するのにかかる時間を10回設定します.
コード#コード#
出力結果
その結果、1000回の在庫削減操作を同時に実行するmysqlはredisより7倍も遅い.
完全なコードを参照https://github.com/zhugw/cocurrent_update_stock/blob/master/src/main/java/com/zhugw/CocurrentUpdateStockApplication.java
商品に在庫がある場合、10000で商品を1つ買うごとに在庫が1つ減ります.
在庫削減はmysqlで実現できます.
update product_stock set stock = stock - 1 where product_id = 1 and stock > 0;
redisを使用して、次のように実装することもできます.
decr 1_stock
(integer) 99
このようなシーンに直面して
redis
を使うと言っています.redis
の同時性能がもっと良いので、実際にこのような考えを検証したいと思っています.在庫を更新してredisとmysqlを比較するのにかかる時間を10回設定します.
コード#コード#
@SpringBootApplication
public class CocurrentUpdateStockApplication implements CommandLineRunner {
@Autowired
private JdbcTemplate jdbcTemplate;
@Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
@Bean
RedisTemplate redisTemplate() {
final RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericToStringSerializer(Long.class));
template.setValueSerializer(new GenericToStringSerializer(Long.class));
return template;
}
public static void main(String[] args) {
SpringApplication.run(CocurrentUpdateStockApplication.class, args);
}
//mysql
private Callable updateStockInMysqlTask = () -> {
final String sql = "update product_stock set stock = stock-1 where product_id=1 and stock>0";
jdbcTemplate.update(sql);
return null;
};
//redis
private Callable updateStockInRedisTask = () -> {
redisTemplate().execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Long decr = connection.decr("1_stock".getBytes());
return decr;
}
});
return null;
};
@Override
public void run(String... args) throws Exception {
final String name = "mysql"; // or "redis"
System.out.printf("start concurrent update stock in %s...%n", name);
List timeList = new ArrayList<>();
for (int i = 0; i < 10; i++) {// 10
long start = System.currentTimeMillis();
concurrentUpdateStock(name); //
long end = System.currentTimeMillis();
System.out.printf("Done. Take time: %d ms%n", end - start);
timeList.add(end - start);
Thread.sleep(1000); // 1
}
System.out.println(timeList.stream().collect(Collectors.summarizingLong(t -> t))); //
}
private void concurrentUpdateStock(String name) throws InterruptedException {
//
int nThreads = 500; //
ExecutorService pool = Executors.newFixedThreadPool(nThreads);
List> tasks = new ArrayList<>();
for (int i = 0; i < nThreads * 2; i++) { //2
if ("mysql".equalsIgnoreCase(name))
tasks.add(updateStockInMysqlTask);
else if ("redis".equalsIgnoreCase(name))
tasks.add(updateStockInRedisTask);
}
List> futureList = pool.invokeAll(tasks); //
while (futureList.stream().anyMatch(f -> !f.isDone())); //
pool.shutdown();
}
}
出力結果
mysql:
LongSummaryStatistics{count=10, sum=11485, min=897, average=1148.500000, max=1458}
redis:
LongSummaryStatistics{count=10, sum=1706, min=95, average=170.600000, max=493}
その結果、1000回の在庫削減操作を同時に実行するmysqlはredisより7倍も遅い.
完全なコードを参照https://github.com/zhugw/cocurrent_update_stock/blob/master/src/main/java/com/zhugw/CocurrentUpdateStockApplication.java