互联网分库分表主键的生成-一个小思路
2016-12-26 00:00
218 查看
摘要: 分库分表主键
几乎所有的大型项目都涉及到分库分表(使用关系型数据库),为了应对递增的数据增长采用分库分表的策略,分库分表后面临的首要问题就是主键的生成。主键的关系涉及几个重要的因素:
1,如果只是做数据存储,没有其他的意义,这样的主键设计会很简单,面临的是后期查询的问题,需要选择是选择什么样的数据类型来存储主键,比如uuid的varchar,序列的bigint等,又或者拼接的结果最终以varchar来存储,考虑的要点是需要怎么最好的使用索引性能来设计实现快速的查询。
2,确保整个系统的分库分表的主键数据唯一,可以采用主键生成器的方式来确保主键唯一,该方案也有很多的方式实现,最常见的就是我们使用mysql的一个表来控制主键的生成,你可以使用序列也可以使用其他的,该方案的缺点是高并发的时候性能会压在该数据库服务器,也可以采用不同的步长增长使用不同的数据库。还有一种是动态的生成Twitter的snowflake算法,该算法已经有很多实现方法,中心思想是一样的,可以上网搜索很多的实现方法。我这里介绍的是基于redis来实现的一个小方案。
3,基于redis实现分布式主键的策略。
redis首先是支持主从复制的,可以确保高可用的,采用服务器的双redis和keepalive实现灾难自动转移。根据情况可以分成不同的主键成成类型采用负载均衡的方法,平摊服务器的压力。并且redis本身是支持事物的,顺便再讲解一下,在分布式系统中使用的分布式锁安全的一种,这里只是小提一下,具体的可以参考redis的官方文档。具体的实现方式有很多种,这里使用一种简单的方式来实现:
该方法只是一个抛砖引玉,你可以采用其他的方式来实现。
几乎所有的大型项目都涉及到分库分表(使用关系型数据库),为了应对递增的数据增长采用分库分表的策略,分库分表后面临的首要问题就是主键的生成。主键的关系涉及几个重要的因素:
1,如果只是做数据存储,没有其他的意义,这样的主键设计会很简单,面临的是后期查询的问题,需要选择是选择什么样的数据类型来存储主键,比如uuid的varchar,序列的bigint等,又或者拼接的结果最终以varchar来存储,考虑的要点是需要怎么最好的使用索引性能来设计实现快速的查询。
2,确保整个系统的分库分表的主键数据唯一,可以采用主键生成器的方式来确保主键唯一,该方案也有很多的方式实现,最常见的就是我们使用mysql的一个表来控制主键的生成,你可以使用序列也可以使用其他的,该方案的缺点是高并发的时候性能会压在该数据库服务器,也可以采用不同的步长增长使用不同的数据库。还有一种是动态的生成Twitter的snowflake算法,该算法已经有很多实现方法,中心思想是一样的,可以上网搜索很多的实现方法。我这里介绍的是基于redis来实现的一个小方案。
3,基于redis实现分布式主键的策略。
redis首先是支持主从复制的,可以确保高可用的,采用服务器的双redis和keepalive实现灾难自动转移。根据情况可以分成不同的主键成成类型采用负载均衡的方法,平摊服务器的压力。并且redis本身是支持事物的,顺便再讲解一下,在分布式系统中使用的分布式锁安全的一种,这里只是小提一下,具体的可以参考redis的官方文档。具体的实现方式有很多种,这里使用一种简单的方式来实现:
public class SequenceNum { //关于redis的使用 private static JedisPool jedisPool; private static Map<String,Integer> dbMap = new ConcurrentHashMap<String,Integer>(); //单例的安全实现如下 private SequenceNum() { //spring整整合redis的链接工程模式 JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory) SpringUtil.getBean("jedisConnectionFactory"); jedisPool = new JedisPool(jedisConnectionFactory.getPoolConfig(), jedisConnectionFactory.getHostName(),jedisConnectionFactory.getPort()); dbMap.put("default", jedisConnectionFactory.getDatabase()); System.out.print("init one"); } private static class SequenceHelper { private static SequenceNum instance = new SequenceNum(); } public static SequenceNum getInstance() { return SequenceHelper.instance; } //下面是需要进行内部缓存处理的数据 private static Map<String, ConcurrentLinkedQueue<Long>> sequenceMap = new ConcurrentHashMap<String, ConcurrentLinkedQueue<Long>>(); private static final long SEQUENCE_NUM = 50; //获得分布式序列的方法 public Long getSequenceNum(String sequence) { Long sequenceNum = -1l; ConcurrentLinkedQueue<Long> sequenceQuene = sequenceMap.get(sequence); if (null != sequenceQuene) { if (sequenceQuene.isEmpty()) { getAndSetQuene(sequence, sequenceQuene); } } else { sequenceQuene = new ConcurrentLinkedQueue<Long>(); sequenceMap.put(sequence, sequenceQuene); getAndSetQuene(sequence, sequenceQuene); } sequenceNum = sequenceQuene.poll(); return sequenceNum; } /** * 重构本地缓存的数据 * @param sequence * @param sequenceQuene */ private synchronize 3ff8 d void getAndSetQuene(String sequence, ConcurrentLinkedQueue<Long> sequenceQuene) { if (!sequenceQuene.isEmpty()) return; try { Jedis jedis = getJedis(sequence); byte [] keys = sequence.getBytes("utf-8"); //使用redis的事物管理 Transaction trans =jedis.multi(); //该redis的健值自增1,是本次的开始位置 Response<Long> start = trans.incr(keys); //redis的最后序列,可以使用区间的方式获得本地的缓存序列 Response<Long> end = trans.incrBy(keys, SEQUENCE_NUM); //提交事务,保证本次的操作是一致性的,当然也可以采用redis的管道来实现 trans.exec(); closeRedis(jedis); for (long i = start.get(); i <= end.get(); i++) { sequenceQuene.add(i); } } catch (Exception e) { e.printStackTrace(); } } //释放redis的连接源 private void closeRedis(Jedis jedis) { jedisPool.returnResourceObject(jedis); } //获得redis的操作源 private Jedis getJedis(String sequence) { Jedis jedis = jedis = jedisPool.getResource(); jedis.select(dbMap.containsKey(sequence) ? dbMap.get(sequence) : dbMap.get("default")); return jedis; } }
该方法只是一个抛砖引玉,你可以采用其他的方式来实现。
相关文章推荐
- 分库分表全局主键生成策略
- 蛙蛙推荐:写一个主键生成组件(服务)
- 如何生成一个新的互联网访问接入点
- 数据库性能优化的五种方案(mycat,基于阿里coba开源的数据库中间件,很容易实现分库分表、主从切换功能。另一个当当网开源的一个库 sharding-jdbc)
- 如何压力测试一个唯一主键函数是否真的不会生成重复主键得方法
- 数据库分库分表(sharding)---全局主键生成策略
- 在客户端使用xslt来解析dom生成网页,不使用js的DOM生成网页,真是一个好思路
- 干货 | 分布式架构系统生成全局唯一序列号的一个思路
- Sharding-JDBC 一个不错的分库分表中间件
- 数据库分库分表(sharding)系列(二) 全局主键生成策略
- 分布式架构系统生成全局唯一序列号的一个思路
- Hibernate保存记录时遇到的一个问题----evitic,not-null配置及主键生成策略
- 数据库分库分表(sharding)系列(二) 全局主键生成策略
- MySQL分库,分表备份的思路和方法
- 数据库分库分表(sharding)(二) 全局主键生成策略
- 数据库分库分表(sharding)系列(二) 全局主键生成策略
- 如何生成一个新的互联网访问接入点
- 数据库分库分表(sharding)系列(二) 全局主键生成策略
- 基于当当开源shardingjdbc的分库分表的配置-单主键分库分表策略配置
- 干货 | 分布式架构系统生成全局唯一序列号的一个思路