flickr主键生成策略

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);
}
发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>