文档章节

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

wangshuaixin
 wangshuaixin
发布于 2016/12/26 16:38
字数 947
阅读 327
收藏 8
点赞 1
评论 0

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

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
大型互联网应用去Oracle改造经验总结——全局id生成服务设计和实现

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

杨武兵
2016/04/01
219
0
方案虽好,成本先行:数据库Sharding+Proxy实践解析

作者介绍 在谈论数据库架构演变和优化时,我们经常会听到分片、分库分表(Sharding)这样的关键词,在很长一段时间内,在各个公司、各中技术论坛里都很热衷谈论各种分片方案,尤其是互联网非...

房晓乐
2017/12/22
0
0
JFinal设置非自增主键问题

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

小99
2016/09/27
372
2
MySQL多数据源笔记5-ShardingJDBC实战

Sharding-JDBC集分库分表、读写分离、分布式主键、柔性事务和数据治理与一身,提供一站式的解决分布式关系型数据库的解决方案。 从2.x版本开始,Sharding-JDBC正式将包名、Maven坐标、码云仓...

狂小白
03/19
0
0
PHPer面试指南-MySQL 篇

本书的 GitHub 地址:https://github.com/todayqq/PHPerInterviewGuide 什么是索引,作用是什么?常见索引类型有那些?Mysql 建立索引的原则? 索引是一种特殊的文件,它们包含着对数据表里所...

angkee
01/24
0
0
分库分表的几种常见形式以及可能遇到的难题

引言 在谈论数据库架构和数据库优化的时候,我们经常会听到“分库分表”、“分片”、“Sharding”…这样的关键词。让人感到高兴的是,这些朋友所服务的公司业务量正在(或者即将面临)高速增...

无寄语
2016/09/09
0
0
备战一线互联网公司Java工程师面试题 (2)

JVM 1、请介绍一下JVM内存模型??用过什么垃圾回收器都说说呗 2、线上发送频繁full gc如何处理? CPU 使用率过高怎么办? 如何定位问题?如何解决说一下解决思路和处理方法 3、知道字节码吗?字节...

j4love
04/14
0
0
MySQL数据迁移工具的设计与实现

一、背景 MySQL作为最流行的关系型数据库产品之一,当数据规模增大遭遇性能瓶颈时,最容易想到的解决方案就是分库分表。无论是进行水平拆分还是垂直拆分,第一步必然需要数据迁移与同步。由此...

stuxuhai
2017/12/08
0
0
分布式系统中的ID生成

问题 在分布式系统中常遇到ID生成问题: 场景1,在分库分表中需要保证某类ID唯一,这样使用主键自增的策略就不再合适 场景2,需要某类ID需要具有同一特性来标识 诸如此类。 方案 有很多解决方...

chaun
2015/12/01
99
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java 重写排序规则,用于代码层级排序

1.dataList 是个List<Map<String,Object>> 类型的数据,所以比较的时候是冲map中获取数据,并且数据不能为空。 2.dataList 类型是由自己定义的,new Comparator<Map<String,Object>> 也是对应......

轻量级赤影
10分钟前
0
0
分布式大型互联网企业架构!

摘要: 开发工具 1.Eclipse IDE:采用Maven项目管理,模块化。 2.代码生成:通过界面方式简单配置,自动生成相应代码,目前包括三种生成方式(增删改查):单表、一对多、树结构。生成后的代码...

明理萝
10分钟前
0
1
对MFC程序的一点逆向分析:定位按钮响应函数的办法

因为消息响应函数保存在AFX_MSGMAP_ENTRY数组中, 观察nMessage、nCode、nID、pfn利用IDA在rdata段中搜索即可, 在IDA中找到代码段基址0x401000,函数地址0x403140, 在WinDbg中运行!addre...

oready
10分钟前
0
0
阻抗匹配与史密斯(Smith)圆图基本原理

参考:http://bbs.eeworld.com.cn/thread-650695-1-1.html

whoisliang
15分钟前
0
0
maven配置文件分离

一、 简介 遇到很多次别人处理的项目,测试环境,本地开发和线上环境的配置不一样,每一次部署都要重新修改配置文件,提交审核代码,才能打包,非常不方便。 其实相信很多人都知道可以使用m...

trayvon
16分钟前
0
0
MacOS和Linux内核的区别

导读 有些人可能认为MacOS和Linux内核有相似之处,因为它们可以处理类似的命令和类似的软件。甚至有人认为苹果的MacOS是基于linux的。事实上,这两个内核的历史和特性是非常不同的。今天,我...

问题终结者
32分钟前
1
0
SpringBoot | 第八章:统一异常、数据校验处理

前言 在web应用中,请求处理时,出现异常是非常常见的。所以当应用出现各类异常时,进行异常的捕获或者二次处理(比如sql异常正常是不能外抛)是非常必要的,比如在开发对外api服务时,约定了响...

oKong
40分钟前
3
0
mysql高级

一、存储引擎 InnoDB MyISAM 比较 二、数据类型 整型 浮点数 字符串 时间和日期 三、索引 索引分类 索引的优点 索引优化 B-Tree 和 B+Tree 原理 四、查询性能优化 五、切分 垂直切分 水平切分...

丁典
今天
1
0
rsync通过同步服务、系统日志、screen工具

rsync通过后台服务同步 在远程主机中建立一个rsync服务器,在服务器上配置好rsync的各种应用,然后将本机作为rsync的一个客户端连接远程的rsync服务器。 首先在A机器上建立并且配置rsync的配...

黄昏残影
今天
5
0
Spring Cloud Gateway 接口文档聚合实现

在微服务架构下,通常每个微服务都会使用Swagger来管理我们的接口文档,当微服务越来越多,接口查找管理无形中要浪费我们不少时间,毕竟懒是程序员的美德。 由于swagger2暂时不支持webflux 走...

冷冷gg
今天
166
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部