文档章节

互联网分库分表主键的生成-一个小思路

wangshuaixin
 wangshuaixin
发布于 2016/12/26 16:38
字数 947
阅读 454
收藏 8

几乎所有的大型项目都涉及到分库分表(使用关系型数据库),为了应对递增的数据增长采用分库分表的策略,分库分表后面临的首要问题就是主键的生成。主键的关系涉及几个重要的因素:

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 synchronized 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;
    }


}

 

该方法只是一个抛砖引玉,你可以采用其他的方式来实现。

© 著作权归作者所有

共有 人打赏支持
wangshuaixin

wangshuaixin

粉丝 13
博文 31
码字总数 29115
作品 1
海淀
技术主管
数据库分库分表(sharding)系列(二) 全局主键生成策略

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案。关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库...

bluishglc
2012/07/03
0
0
数据库之架构:主备+分库?主从+读写分离?

一、数据库架构原则 高可用 高性能 一致性 扩展性 二、常见的架构方案 方案一:主备架构,只有主库提供读写服务,备库冗余作故障转移用    jdbc:mysql://vip:3306/xxdb 高可用分析:高可用...

尜尜人物
08/07
0
0
轻量级数据库中间件利器Sharding-JDBC深度解析

本文根据DBAplus社群第114期线上分享整理而成。 主题简介: 1、关系型数据库中间件核心功能介绍 2、Sharding-JDBC架构及内核解析 3、Sharding-JDBC未来展望 关系型数据库凭借灵活查询的SQL和...

张亮
2017/07/28
0
0
大型互联网应用去Oracle改造经验总结——全局id生成服务设计和实现

ID的特性 id是唯一标识一条数据的,它一般没有什么业务含义,是系统内部的标识,那么它往往有这样一些特性。 全局唯一性。这个是强制的,往往id会被设置成主键,肯定不允许重复。 顺序性。这...

杨武兵
2016/04/01
219
0
JFinal设置非自增主键问题

@波总 ,您好: 由于最近使用了分库分表,主键id去掉了自增,由自己生成,伪代码如下 public Reocrd saveUser(………………){Record user = new Record();long id = genId();user.set("id",...

小99
2016/09/27
372
2

没有更多内容

加载失败,请刷新页面

加载更多

elastic search+kibana 5.6.12安装指南

前提准备: 1,安装jdk, We recommend installing Java version 1.8.0_131 or later. 2, 设置文件最大打开数(使用命令ulimit -n查看) ulimit -n 65536 3, 创建用户elastic/用户组elastic gro...

PageYi
26分钟前
2
0
安装mongodb碰到error: unpacking of archive failed on file /etc/init.d/mongod;5bcec214: cpio: open如何解决

今用yum安装mongodb4.0.3发现一个错误,当用yum install 安装mongo-org 时除了mongodb-org-server 没有安装以外其他的都安装正确,重新安装mongodb-org-server 时报如下错误信息 在一篇老外 ...

chanking
28分钟前
1
0
O2OA:企业办公数字化转型的更佳选择

在全球都在积极探索由新一轮信息技术所引发的第四次工业革命时,一场激发企业内生动力的数字化运动在互联网企业和传统企业之间却呈现出两种截然不同的状态。   传统企业办公数字化不彻底仍...

超能之法师
31分钟前
1
0
基于SylixOS 对 Goahead 进行配置使用 OpenSSL

1. 编译并部署OpenSSL SylixOS支持OpenSSL,git地址为:http://git.sylixos.com/repo/openssl.git 获取OpenSSL工程源码后,导入RealEvo-IDE中编译,编译完成后生成动态库文件和openssl可执行...

Baiqq
33分钟前
1
0
nginx+tomcat均衡负载

一、安装好nginx环境,启动至少两个的tomcat服务; 此处tomcat访问地址为:http://192.168.106.128:1000/、http://192.168.106.128:1001/、http://192.168.106.128:1002/ 二、修改nginx配置文...

狼王黄师傅
34分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部