http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/
测试一下主键生成的性能,通过代码调用生成10万次主键为例。
测试的机器:8G内存,自身跑着7个tomcat,每个分配512M内存。mysql也安装在此机器上。
1、innodb无事务(never)
单线程:746秒,每个请求7.4秒
10线程:540秒,每个请求5.4秒
50线程:耗时太长,2449,每个请求24秒,经过查找,发现是数据库连接池最大数量限制为20影响了性能。把最大连接数改为100,更恶性的事件产生了,DB中的线程竟然开始互相竞争起来,导致严重影响性能。
2、innodb事务
3、MYISAM无事务
单线程:476秒,平均每次请求4.7ms
10线程: 244秒,平均每次请求2.4ms
50线程:237秒,平均每秒2.3ms
100线程:235秒,平均每秒2.3ms
4、MYISAM有事务(MYISAM本身不支持事务,只是测试下spring aop的影响)
单线程:在aop事务中,503秒,每个请求5ms,不在aop事务中,446秒,每秒请求4.4
10线程:在aop事务中,238秒,每个请求2.3秒,不在aop事务中,234秒,每个请求2.3秒
结论:InnoDB是并发数达到一定数据后,DB中锁的竞争厉害。但是myisam表倒没有这种问题,并发数在100时也没有遇到问题。
在aop事务中多少会有一点影响,但本身是myisam表,影响在可接受范围内。
可改进的地方:这次测试只是使用一个表,在flicker中,也介绍了如何分表来分担负载。但对这个项目来说,已经足够满足需求了。暂不考虑分表。
——————————————————————————————
2015.03.09
附下项目中使用的代码:
package cn.joylab.game.service.impl;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.joylab.game.dao2.Ticket32Dao;
import cn.joylab.game.dao2.Ticket64Dao;
import cn.joylab.game.model.Ticket32;
import cn.joylab.game.model.Ticket64;
import cn.joylab.game.service.TicketManager;
@Component("ticketManager")
public class TicketManagerImpl implements TicketManager {
private static final int NUM = 1000;
private AtomicInteger a32 = new AtomicInteger();
private AtomicInteger a32_ = new AtomicInteger();
private AtomicInteger b32 = new AtomicInteger();
private AtomicInteger b32_ = new AtomicInteger();
private AtomicInteger c32 = new AtomicInteger();
private AtomicInteger c32_ = new AtomicInteger();
private AtomicInteger d32 = new AtomicInteger();
private AtomicInteger d32_ = new AtomicInteger();
private AtomicInteger e32 = new AtomicInteger();
private AtomicInteger e32_ = new AtomicInteger();
private AtomicInteger f32 = new AtomicInteger();
private AtomicInteger f32_ = new AtomicInteger();
private AtomicInteger g32 = new AtomicInteger();
private AtomicInteger g32_ = new AtomicInteger();
private AtomicInteger h32 = new AtomicInteger();
private AtomicInteger h32_ = new AtomicInteger();
private AtomicLong a64 = new AtomicLong();
private AtomicLong a64_ = new AtomicLong();
private AtomicLong b64 = new AtomicLong();
private AtomicLong b64_ = new AtomicLong();
private AtomicLong c64 = new AtomicLong();
private AtomicLong c64_ = new AtomicLong();
private AtomicLong d64 = new AtomicLong();
private AtomicLong d64_ = new AtomicLong();
private AtomicLong e64 = new AtomicLong();
private AtomicLong e64_ = new AtomicLong();
private AtomicLong f64 = new AtomicLong();
private AtomicLong f64_ = new AtomicLong();
private AtomicLong g64 = new AtomicLong();
private AtomicLong g64_ = new AtomicLong();
private AtomicLong h64 = new AtomicLong();
private AtomicLong h64_ = new AtomicLong();
public int getNewId32(String stub) {
if ("a".equals(stub)) {
return getNewId32_1(stub, a32, a32_);
} else if ("b".equals(stub)) {
return getNewId32_1(stub, b32, b32_);
} else if ("c".equals(stub)) {
return getNewId32_1(stub, c32, c32_);
} else if ("d".equals(stub)) {
return getNewId32_1(stub, d32, d32_);
} else if ("e".equals(stub)) {
return getNewId32_1(stub, e32, e32_);
} else if ("f".equals(stub)) {
return getNewId32_1(stub, f32, f32_);
} else if ("g".equals(stub)) {
return getNewId32_1(stub, g32, g32_);
} else if ("h".equals(stub)) {
return getNewId32_1(stub, h32, h32_);
} else {
log.error("未解析的字符串:" + stub);
}
return -1;
}
private int getNewId32_1(String stub, AtomicInteger a, AtomicInteger b) {
if (a.get() == 0) {
int id = getNewId32_2(stub);
a.set(id);
b.set(NUM);
return id * NUM;
}
int i = b.decrementAndGet();
if (i > 0) {
return a.get() * NUM + (NUM - i);
} else {
int id = getNewId32_2(stub);
a.set(id);
b.set(NUM);
return id * NUM;
}
}
private int getNewId32_2(String stub) {
Ticket32 ticket32 = new Ticket32();
ticket32.setStub(stub);
if ("a".equals(stub)) {
ticket32Dao.getNewId_a(ticket32);
} else if ("b".equals(stub)) {
ticket32Dao.getNewId_b(ticket32);
} else if ("c".equals(stub)) {
ticket32Dao.getNewId_c(ticket32);
} else if ("d".equals(stub)) {
ticket32Dao.getNewId_d(ticket32);
} else if ("e".equals(stub)) {
ticket32Dao.getNewId_e(ticket32);
} else if ("f".equals(stub)) {
ticket32Dao.getNewId_f(ticket32);
} else if ("g".equals(stub)) {
ticket32Dao.getNewId_g(ticket32);
} else if ("h".equals(stub)) {
ticket32Dao.getNewId_h(ticket32);
} else {
log.error("未解析的字符串:" + stub);
}
return ticket32.getId();
}
public long getNewId64(String stub) {
if ("a".equals(stub)) {
return getNewId64_1(stub, a64, a64_);
} else if ("b".equals(stub)) {
return getNewId64_1(stub, b64, b64_);
} else if ("c".equals(stub)) {
return getNewId64_1(stub, c64, c64_);
} else if ("d".equals(stub)) {
return getNewId64_1(stub, d64, d64_);
} else if ("e".equals(stub)) {
return getNewId64_1(stub, e64, e64_);
} else if ("f".equals(stub)) {
return getNewId64_1(stub, f64, f64_);
} else if ("g".equals(stub)) {
return getNewId64_1(stub, g64, g64_);
} else if ("h".equals(stub)) {
return getNewId64_1(stub, h64, h64_);
} else {
log.error("未解析的字符串:" + stub);
}
return -1;
}
private long getNewId64_1(String stub, AtomicLong a, AtomicLong b) {
if (a.get() == 0) {
long id = getNewId64_2(stub);
a.set(id);
b.set(NUM);
return id * NUM;
}
long i = b.decrementAndGet();
if (i > 0) {
return a.get() * NUM + (NUM - i);
} else {
long id = getNewId64_2(stub);
a.set(id);
b.set(NUM);
return id * NUM;
}
}
private long getNewId64_2(String stub) {
Ticket64 ticket64 = new Ticket64();
ticket64.setStub(stub);
if ("a".equals(stub)) {
ticket64Dao.getNewId_a(ticket64);
} else if ("b".equals(stub)) {
ticket64Dao.getNewId_b(ticket64);
} else if ("c".equals(stub)) {
ticket64Dao.getNewId_c(ticket64);
} else if ("d".equals(stub)) {
ticket64Dao.getNewId_d(ticket64);
} else if ("e".equals(stub)) {
ticket64Dao.getNewId_e(ticket64);
} else if ("f".equals(stub)) {
ticket64Dao.getNewId_f(ticket64);
} else if ("g".equals(stub)) {
ticket64Dao.getNewId_g(ticket64);
} else if ("h".equals(stub)) {
ticket64Dao.getNewId_h(ticket64);
} else {
log.error("未解析的字符串:" + stub);
}
return ticket64.getId();
}
@Autowired
private Ticket32Dao ticket32Dao;
@Autowired
private Ticket64Dao ticket64Dao;
private static final Log log = LogFactory.getLog(TicketManagerImpl.class);
}
近期评论