首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >短连服务crud(第十八章/十九章/二十章/二十一章)海量数据处理-商用短链

短连服务crud(第十八章/十九章/二十章/二十一章)海量数据处理-商用短链

作者头像
高大北
发布2022-09-23 16:00:51
4870
发布2022-09-23 16:00:51
举报

第十八章 短链服务-业务需求和短链码解决方案讲解

第1集 短链服务介绍和应用场景讲解

简介: 短链服务介绍和应用场景讲解

  • 什么是短链服务
image-1661248948520
image-1661248948520
  • 业务背景:为啥需要短链
    • 公司电商产品推广、业务活动页、广告落地页 缺少实时【数据反馈和渠道效果分析】
    • 老项目业务推广【没人维护,无法做埋点】需要统计效果
    • APP和营销活动发送营销短信链接过长,【浪费短信发送费用】
    • 国内【反垄断后】微信、抖音、淘宝 流量互通,很多知识付费公司需要做 私域流量、社群运营
    • 可以对外做产品输出,实现商业化能力增加公司营收
    • 积累终端数据和人群数据,为公司未来产品人群做策略助力
    • 更多。。。。
  • 短链组成
    • 协议://短链域名/短链码
  • 最简单的方式
    • 一个短链编码,去数据库select * from table where code =XXX,返回给用户就行
    image-1661248963819
    image-1661248963819
第2集 需求出发-带你详细一个短链的生命周期

简介: 需求出发带你详细一个短链的生命周期

  • 创建者和访问者
image-1661248974345
image-1661248974345
  • 创建者(UI图大体类似哈)
    • 流量包管理
      • 免费流量包
      • 付费流量包
      image-1661248988457
      image-1661248988457
    • 分组管理
      • 新增分组
      • 删除分组
      • 修改分组
      • 查看分组下的短链
image-1661249004612
image-1661249004612
  • 短链管理
    • 创建短链
      • 目标地址
      • 短链标题
      • 短链域名
      • 所属分组
      • 有效期
      image-1661249014765
      image-1661249014765
  • 删除短链
    • 修改短链
    • 查看短链
      • 访问PV、UV
      • 地域分布
      • 时间分布
      • 来源分布
  • 访问者
    • 访问短链
    • 跳转目标站点
第3集 短链服务生成短链URL的问题你能想到多少

简介: 短链URL生成服务里面的问题你能想到多少

  • 短链码如何生成
image-1661249034761
image-1661249034761
  • 需要解决的问题(自己是技术Leader,能否想到这些问题,并解决。做架构设计之前,要想清楚)
    • 问题一:长链的关系和短链的关系
      • 一对一?
      • 一对多?
      • 多对多?
    • 问题二:前端访问短链是如何跳转到对应的页面的?
    • 问题三:短链码是如何生成的
      • 知道几种方式?
    • 问题四:SaaS类型业务,数据量有多大,是否要分库分表
    • 问题五:如果分库分表,PartitionKey是哪个?使用怎样的策略
    • 问题六:如果分库分表,访问短链怎么知道具体是哪个库哪个表?
    • 问题七:如果分库分表,怎么查看某个账号创建的全部短链?
第4集 短链服务问题解决方案讲解-业务关系+跳转问题

简介: 短链服务问题解决方案讲解-业务关系+跳转问题

问题一:长链的关系和短链的关系是一对一还是一对多?

  • 一个长链,在不同情况下,生成的短网址应该不一样,才不会造成冲突
  • 多渠道推广下,也可以区分统计不同渠道的效果质量
  • 所以是 一个短链接只能对应一个长链接,当然一个长链接可以对应多个短链接

问题二:前端访问短链是如何跳转到对应的页面的?

服务端转发

  • 由服务器端进行的页面跳转,刚学Servlet时, 从OneServlet中转发到TwoServlet
  • 地址栏不发生变化,显示的是上一个页面的地址
  • 请求次数:只有1次请求
  • 转发只能在同一个应用的组件之间进行,不可以转发给其他应用的地址
 request.getRequestDispatcher("/two").forward(request, response); 
image-1661249053707
image-1661249053707
  • 页面的跳转-重定向
    • 由浏览器端进行的页面跳转
image-1661249062896
image-1661249062896
  • 重定向涉及到3xx状态码,访问跳转是301还是302,301和302代表啥意思?
    • 301 是永久重定向
      • 会被浏览器硬缓存,第一次会经过短链服务,后续再访问直接从浏览器缓存中获取目标地址
    • 302 是临时重定向
      • 不会被浏览器硬缓存,每次都是会访问短链服务
    • 短地址一经生成就不会变化,所以用 301 是同时对服务器压力也会有一定减少
    • 但是如果使用了 301,无法统计到短地址被点击的次数
    • 所以选择302虽然会增加服务器压力,但是有很多数据可以获取进行分析
    • 选择使用302,这个也可以对违规推广的链接进行实时封禁
第5集 短链服务问题解决方案讲解-短链码生成解决方案《上》

简介: 短链服务问题解决方案讲解-短链码生成解决方案《上》

问题三:短链码如何是如何生成的

短链码特点

  • 生成性能强劲
  • 碰撞概率低
    • 避免重复
    • 恶意猜测
  • 业务规则安全
image-1661249078168
image-1661249078168

方式

  • 自增ID
    • 利用插入数据库,利用数据库自增id
    • 把自增id转成62进制作为短链码
    • 短链码的长度不固定,随着 id 变大,短链码长度也增长
    • 可以指定从某个长度开始增长,到百亿、千亿数量
    • 转换工具:https://tool.lu/hexconvert/
    • 是否存在重复: 不重复
    • 但短链码是有序的递增,存在【业务数据安全】问题

MD5内容压缩

  • 长链接做md5加密
43E08496,9E5CF455,E6D2D2B3,3407A6D2
  • 加密串查询是否已经生成过短链接
    • 如果已经存在,则拼接时间戳再MD5加密,插入数据库
    • 如果不存在则把长链接、长链接加密串插入数据库
  • 取MD5后 最后1 个 8 位字符串作为短链码
  • 是否存在重复: 存在碰撞(重复)可能
  • 是有损压缩算法,数据量超大情况碰撞概念越大
    • 比如 【小滴课堂-老王的女友】有300多个,每再多1个,再同一天生日的概率越大,就更加复杂
第6集 【重要】敏感数据+自增ID暴露的商业秘密

简介: 敏感数据讲解+自增ID暴露的商业秘密

什么是数据脱敏

  • 也叫数据的去隐私化,在给定脱敏规则和策略的情况下,对敏感数据比如 手机号身份证 等信息,进行转换或者修改的一种技术手段,防止敏感数据直接在不可靠的环境下使用和泄露、撞库等
  • 技术分两类
    • 静态数据脱敏
      • 将生产数据导出,进行对外发送或者给开发、测试人员等
    • 动态数据脱敏
      • 程序直接连接生产数据的场景,如运维人员在运维的工作中直接连接生产数据库进行运维
      • 客服人员在生产中通过后台查询的个人信息

数据库业务规则安全:自增ID暴露的商业秘密

背景

作为后端开发人员肯定离不开数据库设计,尽管你知道数据安全、接口安全、网络安全,但你也很大可能不小心暴露的公司的核心机密。 

【做空上市公司的股票】如果你有炒股,那你知道如果这个数据库设计漏洞被他人知道,就可以做空一个上司公司的股票的不?
【摧毁对手的利器】如果一个公司在是靠业务数据来说话的,如果被他人知道,在核心的时间点,被披露出来,那融资可能凉凉,企业可能面临倒闭。

在某天一个竞争对手 老王 做竞品调研的时候,注册了你公司的应用

【暴露了总用户量】

通过业务接口抓包分析(假定数据没做加密或者加密被破解了),被他发现了自增id这个事情,他好几个号注

册了,编号都是一百多万,每次id都是自增1, 用户量最多100多万,就此暴雷了。

经过有经验的人知道不能对外暴露id这个事情,但是总有关联的业务,或者其他不知道的人员开发了对应

的功能,比如 订单表、记录表、收藏表或者其他和user_id有关联的,只要他操作业务,接口有返回user_id,就容易出问题了。
【暴露了每日拉新数据】
如果是用户自增id,老王 肯定不单停留这里这么简单,假如他想看这个产品每日新增的用户有多少。

毕竟拉新这个指标是很多公司都离不开的,比如通过投放广告、买量业务等等去获取新用户。

老王想看下这个公司每天新增用户量大不大,他就今天注册一个看id多少,明天再注册一个看id多少;

通过一段时间内去统计每天递增的值,老王就可以推断出平台新增用户大概是多少了,公司的拉新能力如何。
【暴露了平台商品数量-订单数量】

同样的思路,去爬取电商平台的商品,爬取平台最大的商品id, 第二天再次爬取,持续一段时间。就可以可以推断出新品发布数量。

同样的思路,去抓取订单接口,看最大id是多少, 第二天再次爬取,持续一段时间。就可以推断出这个公司的每天订单量有多大。

结语:

  • 看到这里,你觉得你公司的自增id敢不敢乱用,是不是不但只是技术那么简单了。
  • 合格的架构,不单止某个技术厉害,更要考虑和业务-商业上的结合。
  • 正常的业务表,会用自增id,但是也会加个业务id,比如下面的
CREATE TABLE `USER` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `biz_id` varchar(64) DEFAULT NULL COMMENT '业务id',
  `name` varchar(128) DEFAULT NULL COMMENT '昵称',
  `pwd` varchar(124) DEFAULT NULL COMMENT '密码',
  `head_img` varchar(524) DEFAULT NULL COMMENT '头像',
  `phone` varchar(64) DEFAULT '' COMMENT '手机号',
  `login_type` int(10) DEFAULT NULL COMMENT '登录类型',
  `email` varchar(128) DEFAULT NULL COMMENT '邮箱',
  `sex` tinyint(2) DEFAULT '1' COMMENT '0表示女,1表示男',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `roles` varchar(11) DEFAULT NULL COMMENT '1,2,3,数字权限,逗号分隔',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=100000 DEFAULT CHARSET=utf8;


增加了 biz_id,这个就是业务id, 如果有关联,则用 biz_id进行关联并返回,这个可以是varchar类型,long雪花算法.

其实最靠谱的就是,不要把有业务规则的id暴露给用户,不止id字段,类似的敏感字段都是
第7集 短链服务问题解决方案讲解-短链码生成解决方案《下》

简介: 短链URL服务问题解决方案讲解-短链码生成解决方案《下》

哈希算法:将一个元素映射成另一个元素

  • 加密哈希,如SHA256、MD5(上集讲了)
  • 非加密哈希,如MurMurHash,CRC32

MurMurHash

Murmur哈希是一种非加密散列函数,适用于一般的基于散列的查找。
它在2008年由Austin Appleby创建,在Github上托管,名为“SMHasher” 的测试套件。 
它也存在许多变种,所有这些变种都已经被公开。 
该名称来自两个基本操作,乘法(MU)和旋转(R)--来自百科

是一种【非加密型】哈希函数且【随机分布】特征表现更良好

由于是非加密的哈希函数,性能会比MD5强

再很多地方都用到比如Guava、Jedis、HBase、Lucence等

存在两个版本

  • MurmurHash2(产生32位或64位值)
  • MurmurHash3(产生32位或128位值)

数据量

  • MurmurHash的 32 bit 能表示的最大值近 43 亿的10进制
    • 满足多数业务,如果接近43亿则冲突概率大
  • 产品目标【超理想情况】
首年日活用户: 10万

首年日新增短链数据:10万*50 = 500万

年新增短链数:500万 * 365天 = 18.2亿 

年新增用户数:50万/1年

年营收目标: 10万付费用户 * 客单价200元 = 2千万

新增短链:50条/用户每日
  • MurMurHash得到的数值是10进制,一般会转化为62进制进行缩短
  • 常规短链码是6~8位数字+大小写字母组合
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

6 位 62 进制数可表示 568 亿个短链(62的6次方,每位都有62个可能,如果扩大位数到7位,则可以支持3万5200亿)
  • MurmurHash的 32 bit 满足多数业务 43亿
    • 拼接上库-表位则可以表示更多数据(后续会讲分库分表的,库表位)
    • 7位则可以到到 43亿 * 62 = 2666亿
    • 8位则可以到到 2666亿 * 62 = 1.65万亿条数据
    • 结合短链过期数据归档,理论上满足未来全部需求了
  • 数据库存储
    • 单表1千万 * 62个库 * 62表 = 384亿数据

第十九章 短链服务-Murmur哈希算法封装组件

第1集 Guava框架里面的Murmur哈希算法测试

简介: Guava框架里面的Murmur哈希算法测试

  • Guava框里里面自带Murmur算法
  • 单元测试
@Test
    public void testMurmurHash() {
        for (int i = 0; i < 50; i++) {
            int num1 = random.nextInt(1000000);
            int num2 = random.nextInt(1000000);
            int num3 = random.nextInt(1000000);
            String originalUrl = num1 + "xdclass+" + num2 + ".net" + num3;
            long murmur3_32 = Hashing.murmur3_32().hashUnencodedChars(originalUrl).padToLong();
            System.out.println("murmur3_32="+murmur3_32);

        }

    }
  • CommonUtil工具类
  /**
     * murmur hash算法
     * @param param
     * @return
     */
    public static long murmurHash32(String param){
        long murmur32 = Hashing.murmur3_32().hashUnencodedChars(param).padToLong();
        return murmur32;
    }
第2集 短链生成组件ShortLinkComponent封装

简介: 短链生成组件ShortLinkComponent封装

  • 创建短链组件类 ShortLinkComponent
    /**
     * 创建短链
     * @param originalUrl
     * @return db编码+6位短链编码
     */
    public String createShortLinkCode(String originalUrl){
        long murmur32 = CommonUtil.murmurHash32(originalUrl);
        //转62进制
        String shortLinkCode = encodeToBase62(murmur32);
        return code;
    }
  • 10进制转62进制
private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /**
     * 10进制转62进制
     * @param num
     * @return
     */
    private static String encodeToBase62(long num) {
        //StringBuffer:线程安全;    StringBuilder:线程不安全
        StringBuffer sb = new StringBuffer();
        do {
            int i = (int) (num % 62);
            sb.append(CHARS.charAt(i));
            num /= 62;
            // num = num/ 62;
        } while (num > 0);

        String value = sb.reverse().toString();
        return value;
    }
第3集 组件ShortLinkComponent测试和疑惑解答

简介: 组件ShortLinkComponent测试和疑惑解答

  • 单元测试
    /**
     * 测试短链平台
     */
    @Test
    public void testCreateShortLink() {
        Random random = new Random();
        for (int i = 0; i < 100; i++) {
            int num1 = random.nextInt(10);
            int num2 = random.nextInt(1000000);
            int num3 = random.nextInt(1000000);
            String originalUrl = num1 + "xdclass" + num2 + ".net" + num3;
            String shortLinkCode = shortLinkComponent.createShortLinkCode(originalUrl);
            log.info("originalUrl:" + originalUrl + ", shortLinkCode=" + shortLinkCode);
        }
    }
  • 为什么要用62进制转换,不是64进制?
    • 62进制转换是因为62进制转换后只含数字+小写+大写字母
    • 而64进制转换会含有/、+这样的符号(不符合正常URL的字符)
    • 10进制转62进制可以缩短字符,如果我们要6位字符的话,已经有560亿个组合了
  • 看业务情况有些短链也会加入其它特殊字符
    • 短链固定6位?肯定不是的,后续会进行分库分表改造
    image-1661249152154
    image-1661249152154

第二十章 短链服务-数据库表建立和业务代码开发

第1集 数据库表模型讲解-短链分组和短链

简介: 数据库表模型讲解-短链分组和短链

  • 关系
    • 一个账号有多个分组
    • 一个分组下有多个短链
    image-1661249167471
    image-1661249167471
    • 短链-分组
CREATE TABLE `link_group` (
  `id` bigint unsigned NOT NULL,
  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '组名',
  `account_no` bigint DEFAULT NULL COMMENT '账号唯一编号',
  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP,
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
  • 短链
CREATE TABLE `short_link` (
  `id` bigint unsigned NOT NULL ,
  `group_id` bigint DEFAULT NULL COMMENT '组',
  `title` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '短链标题',
  `original_url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '原始url地址',
  `domain` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '短链域名',
  `code` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '短链压缩码',
  `sign` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '长链的md5码,方便查找',
  `expired` datetime DEFAULT NULL COMMENT '过期时间,长久就是-1',
  `account_no` bigint DEFAULT NULL COMMENT '账号唯一编号',
  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `del` int unsigned NOT NULL COMMENT '0是默认,1是删除',
  `state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '状态,lock是锁定不可用,active是可用',
  `link_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '链接产品层级:FIRST 免费青铜、SECOND黄金、THIRD钻石',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
第2集 MybatisPlus逆向工具生成短链服务相关java对象

简介: MybatisPlus逆向工具生成短链服务相关java对象

  • 配置代码
public class MyBatisPlusGenerator {

    public static void main(String[] args) {
        //1. 全局配置
        GlobalConfig config = new GlobalConfig();
        // 是否支持AR模式
        config.setActiveRecord(true)
                // 作者
                .setAuthor("二当家小D")
                // 生成路径,最好使用绝对路径,window路径是不一样的
                //TODO  TODO  TODO  TODO
                .setOutputDir("/Users/xdclass/Desktop/demo/src/main/java")
                // 文件覆盖
                .setFileOverride(true)
                // 主键策略
                .setIdType(IdType.AUTO)

                .setDateType(DateType.ONLY_DATE)
                // 设置生成的service接口的名字的首字母是否为I,默认Service是以I开头的
                .setServiceName("%sService")

                //实体类结尾名称
                .setEntityName("%sDO")

                //生成基本的resultMap
                .setBaseResultMap(true)

                //不使用AR模式
                .setActiveRecord(false)

                //生成基本的SQL片段
                .setBaseColumnList(true);

        //2. 数据源配置
        DataSourceConfig dsConfig = new DataSourceConfig();
        // 设置数据库类型
        dsConfig.setDbType(DbType.MYSQL)
                .setDriverName("com.mysql.cj.jdbc.Driver")
                //TODO  TODO  TODO  TODO
                .setUrl("jdbc:mysql://120.79.150.146:3306/dcloud_link?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai")
                .setUsername("root")
                .setPassword("xdclass.net168");

        //3. 策略配置globalConfiguration中
        StrategyConfig stConfig = new StrategyConfig();

        //全局大写命名
        stConfig.setCapitalMode(true)
                // 数据库表映射到实体的命名策略
                .setNaming(NamingStrategy.underline_to_camel)

                //使用lombok
                .setEntityLombokModel(true)

                //使用restcontroller注解
                .setRestControllerStyle(true)

                // 生成的表, 支持多表一起生成,以数组形式填写
                //TODO  TODO  TODO  TODO
                .setInclude("link_group","short_link");

        //4. 包名策略配置
        PackageConfig pkConfig = new PackageConfig();
        pkConfig.setParent("net.xdclass")
                .setMapper("mapper")
                .setService("service")
                .setController("controller")
                .setEntity("model")
                .setXml("mapper");

        //5. 整合配置
        AutoGenerator ag = new AutoGenerator();
        ag.setGlobalConfig(config)
                .setDataSource(dsConfig)
                .setStrategy(stConfig)
                .setPackageInfo(pkConfig);

        //6. 执行操作
        ag.execute();
        System.out.println("======= 小滴课堂 Done 相关代码生成完毕  ========");
    }
}
  • 导入生成好的代码
    • model (为啥不放common项目,如果是确定每个服务都用到的依赖或者类才放到common项目)
    • mapper 类接口拷贝
    • resource/mapper文件夹 xml脚本拷贝
    • controller
    • service 不拷贝
第3集 同学遇到的坑-配置文件修改-yml转properties

简介: 配置文件修改-yml转properties

  • SpringBoot的配置文件有两种
    • 一种是properties结尾的
    • 一种是yaml或者yml文件结尾的
    • 如果同时存在properties和yml, application.properties里面的属性就会覆盖里application.yml的属性
  • yml的注意点
    • yml中缩进一定不能使用TAB,否则会报很奇怪的错误
    • yml每个的冒号后面一定都要加一个空格
    • 第一个是yml是支持中文内容的,properties想使用中文需要unicode编码
  • 账号服务配置转换
server.port=8001
spring.application.name=dcloud-account

#----------服务注册和发现--------------
spring.cloud.nacos.discovery.server-addr=120.79.150.146:8848
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos

#-------redis连接配置-------
spring.redis.client-type=jedis
spring.redis.host=120.79.150.146
spring.redis.password=xdclass.net
spring.redis.port=6379
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=100
spring.redis.jedis.pool.max-wait=60000

#-------分库分表数据源配置-------
spring.shardingsphere.datasource.names=ds0
spring.shardingsphere.datasource.ds0.connectionTimeoutMilliseconds=30000
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.idleTimeoutMilliseconds=60000
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://120.79.150.146:3306/dcloud_account?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.maintenanceIntervalMilliseconds=30000
spring.shardingsphere.datasource.ds0.maxLifetimeMilliseconds=1800000
spring.shardingsphere.datasource.ds0.maxPoolSize=50
spring.shardingsphere.datasource.ds0.minPoolSize=50
spring.shardingsphere.datasource.ds0.password=xdclass.net168
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.props.sql.show=true

# 指定traffic表的数据分布情况,配置数据节点,行表达式标识符使用 ${...} 或 $->{...},但前者与 Spring 本身的文件占位符冲突,所以在 Spring 环境中建议使用 $->{...}
spring.shardingsphere.sharding.tables.traffic.actual-data-nodes=ds0.traffic_$->{0..1}
#水平分表策略+行表达式分片
spring.shardingsphere.sharding.tables.traffic.table-strategy.inline.algorithm-expression=traffic_$->{ account_no % 2 }
spring.shardingsphere.sharding.tables.traffic.table-strategy.inline.sharding-column=account_no

#id生成策略
spring.shardingsphere.sharding.tables.traffic.key-generator.column=id
spring.shardingsphere.sharding.tables.traffic.key-generator.props.worker.id=${workId}
spring.shardingsphere.sharding.tables.traffic.key-generator.type=SNOWFLAKE

#----------sms短信配置--------------
sms.app-code=6999d4df3e7d48028470bbe517169a8d
sms.template-id=M72CB42894

#----------阿里云OSS配置--------------
aliyun.oss.endpoint=oss-cn-321.aliyuncs.com
aliyun.oss.access-key-id=312
aliyun.oss.access-key-secret=123
aliyun.oss.bucketname=dcloud-link
  • 短链服务相关配置文件(复制账号微服务配置修改)
第4集 短链分组管理-CURD接口开发实战《上》

简介: 短链分组管理-CURD接口开发实战《上》

  • 配置登录拦截器
  • 新增接口
  • 删除接口
第5集 短链分组管理-CURD接口开发实战《下》

简介: 短链分组管理-CURD接口开发实战《下》

  • 查询详情
  • 查询用户全部分组
  • 更新分组接口
第6集 短链分组管理-水平分库分表配置实战《青铜玩法》

简介: 短链分组管理-水平分库分表配置实战

  • 需求
    • 未来2年,短链平台累计5百万用户
      • 短链组:一个用户30个组,就是1.5亿个组
      • 单表不超过1千万数据,需要分15张表
      • 进一步延伸,进行水平分库分表,比如 2库、4库、8库、16库
      • 一个库一张表
    • 需要降低单表数据量,进行水平分库分表
    • 分库数量:线上分16库,本地分2库即可
    • 分片key: account_no,查询维度都是根据account_no进行查询
    • 分片策略:行表达式分片策略 InlineShardingStrategy
  • 配置
#----------短链组,策略:水平分库,不水平分表--------------
# 先进行水平分库, 水平分库策略,行表达式分片
spring.shardingsphere.sharding.tables.link_group.database-strategy.inline.sharding-column=account_no
spring.shardingsphere.sharding.tables.link_group.database-strategy.inline.algorithm-expression=ds$->{account_no % 2}

第二十一章 短链服务分库分表-如何做到扩容免数据迁移《黄金玩法》

第1集 短链服务-ShortLink分库分表解决方案讲解《青铜》

简介: 短链服务-ShortLink分库分表解决方案讲解

  • 前言
    • 因为有些参数是和购买大课支付订单绑定,每周动态更新,小滴课堂官网开通权限
    • 所以买了盗版的同学没法实操重要环节的内容。
    • 如果发现你买了盗版,帮我举报。联系我这边这边大课会有特殊折扣优惠
    • 加我微信,都是学习的同学,小的付出带来涨薪和技术增长,6分之1以上月薪即可回本
    • 群里的学习氛围-技术讨论也是盗版没法给到的
image-20210421143515942
image-20210421143515942

短链分库分表-小滴课堂老王 同学想到的

  • 老王同学:老师,很容易的,前面学了那么多直接用Inline进行分库分表
image-1661249238374
image-1661249238374

数据量预估

首年日活用户: 10万

首年日新增短链数据:10万*50 = 500万

年新增短链数:500万 * 365天 = 18.2亿

往高的算就是100亿,支撑3年

分库分表策略

分库分表

  • 16个库, 每个库64个表,总量就是 1024个表

分片键:短链码 code

  • 比如 g1.fit/92AEva 的短链码 92AEva

分库分表算法:短链码进行hash取模

库ID = 短链码hash值 % 库数量  
表ID = 短链码hash值 / 库数量  % 表数量

优点

  • 保证数据较均匀的分散落在不同的库、表中,可以有效的避免热点数据集中问题,
  • 分库分表方式清晰易懂

问题

  • 扩容不是很方便,需要数据迁移
  • 需要一次性建立16个库, 每个库64个表,总量就是 1024个表,浪费资源
第2集 短链服务-分库分表扩容免数据迁移解决方案讲解《黄金玩法》

简介: 短链服务-分库分表免迁移扩容解决方案讲解《黄金玩法》

  • 需要解决的问题
    • 数据量增加,扩容避免迁移数据或者免迁移
    • 前期数据量不多,不浪费库表系统资源
      • 分库分表:16个库, 每个库64个表,总量就是 1024个表
    • 讨论区直达
    • 强调一遍
      • 一定要自己多思考,我说的也不一定对,留坑也说不准
      • 要反驳我的内容,才能提高自己的能力
      • 真心要求大家提高自己的思考能力,不能我说啥就听啥
      • 举一反三,才是咱们小滴课堂出来的同学,真正靠技术说话的人
image-1661249258077
image-1661249258077
  • 短链码
    • 比如 g1.fit/92AEva 的短链码 92AEva
  • 如何做?
    • 从短链码入手-增加库表位
    • 类似案例-阿里这边商品订单号-里面也包括了库表信息(规则不能说)
image-1661249269549
image-1661249269549
第3集 短链服务-分库分表相关库表建立

简介: 短链服务-分库分表相关库表建立

  • 为啥能做到免迁移扩容?
    • A92AEva1
    • 由于短链码的前缀和后缀是是固定的,所以扩容也不影响旧的数据
    • 类似的免迁移扩容策略还有哪些?
      • 时间范围分库分表
      • id范围分库分表
  • 三个库
  • 一个库两个表
  • properties配置多库表
spring.shardingsphere.datasource.names=ds0,ds1,dsa

#ds0配置
spring.shardingsphere.datasource.ds0.connectionTimeoutMilliseconds=30000
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.idleTimeoutMilliseconds=60000
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://120.79.150.146:3306/dcloud_link_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.maintenanceIntervalMilliseconds=30000
spring.shardingsphere.datasource.ds0.maxLifetimeMilliseconds=1800000
spring.shardingsphere.datasource.ds0.maxPoolSize=50
spring.shardingsphere.datasource.ds0.minPoolSize=50
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=xdclass.net168

#ds1配置
spring.shardingsphere.datasource.ds1.connectionTimeoutMilliseconds=30000
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.idleTimeoutMilliseconds=60000
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://120.79.150.146:3306/dcloud_link_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.maintenanceIntervalMilliseconds=30000
spring.shardingsphere.datasource.ds1.maxLifetimeMilliseconds=1800000
spring.shardingsphere.datasource.ds1.maxPoolSize=50
spring.shardingsphere.datasource.ds1.minPoolSize=50
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=xdclass.net168


#dsa配置
spring.shardingsphere.datasource.dsa.connectionTimeoutMilliseconds=30000
spring.shardingsphere.datasource.dsa.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.dsa.idleTimeoutMilliseconds=60000
spring.shardingsphere.datasource.dsa.jdbc-url=jdbc:mysql://120.79.150.146:3306/dcloud_link_a?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.dsa.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.dsa.maintenanceIntervalMilliseconds=30000
spring.shardingsphere.datasource.dsa.maxLifetimeMilliseconds=1800000
spring.shardingsphere.datasource.dsa.maxPoolSize=50
spring.shardingsphere.datasource.dsa.minPoolSize=50
spring.shardingsphere.datasource.dsa.username=root
spring.shardingsphere.datasource.dsa.password=xdclass.net168
第4集 短链服务水平分库分表实战-标准分片策略-精准分片算法《上》

简介: 短链服务分库分表实战-标准分片策略-精准分片算法

  • 水平分库-标准分片策略-精准分片算法 Ae23asa1
public class CustomDBPreciseShardingAlgorithm implements PreciseShardingAlgorithm<String> {

    /**
     * @param availableTargetNames 数据源集合
     *                             在分库时值为所有分片库的集合 databaseNames
     *                             分表时为对应分片库中所有分片表的集合 tablesNames
     * @param shardingValue        分片属性,包括
     *                             logicTableName 为逻辑表,
     *                             columnName 分片健(字段),
     *                             value 为从 SQL 中解析出的分片健的值
     * @return
     */

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {

        //获取短链码第一位,即库位
        String codePrefix = shardingValue.getValue().substring(0, 1);

        for (String targetName : availableTargetNames) {
            //获取库名的最后一位,真实配置的ds
            String targetNameSuffix = targetName.substring(targetName.length() - 1);

            //如果一致则返回
            if (codePrefix.equals(targetNameSuffix)) {
                return targetName;
            }
        }

        //抛异常
        throw new BizException(BizCodeEnum.DB_ROUTE_NOT_FOUND);

    }
}
  • 配置
#----------短链,策略:分库+分表--------------
# 先进行水平分库,然后再水平分表
spring.shardingsphere.sharding.tables.short_link.database-strategy.standard.sharding-column=code
spring.shardingsphere.sharding.tables.short_link.database-strategy.standard.precise-algorithm-class-name=net.xdclass.strategy.CustomDBPreciseShardingAlgorithm
第5集 短链服务水平分库分表实战-标准分片策略-精准分片算法《下》

简介: 短链服务分库分表实战-标准分片策略-精准分片算法

  • 水平分表-标准分片策略-精准分片算法
public class CustomTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<String> {

    /**
     * @param availableTargetNames 数据源集合
     *                             在分库时值为所有分片库的集合 databaseNames
     *                             分表时为对应分片库中所有分片表的集合 tablesNames
     * @param shardingValue        分片属性,包括
     *                             logicTableName 为逻辑表,
     *                             columnName 分片健(字段),
     *                             value 为从 SQL 中解析出的分片健的值
     * @return
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {


        //获取逻辑表名
        String targetName = availableTargetNames.iterator().next();

        String value = shardingValue.getValue();
        //短链码最后一位
        String codePrefix = value.substring(value.length()-1);
        //拼装actual table
        return targetName + "_" + codePrefix;

    }
}
  • 配置文件
# 水平分表策略,自定义策略。   真实库.逻辑表
spring.shardingsphere.sharding.tables.short_link.actual-data-nodes=ds0.short_link,ds1.short_link,dsa.short_link
spring.shardingsphere.sharding.tables.short_link.table-strategy.standard.sharding-column=code
spring.shardingsphere.sharding.tables.short_link.table-strategy.standard.precise-algorithm-class-name=net.xdclass.strategy.CustomTablePreciseShardingAlgorithm

#id生成策略
spring.shardingsphere.sharding.tables.short_link.key-generator.column=id
spring.shardingsphere.sharding.tables.short_link.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.short_link.key-generator.props.worker.id=${workerId}
第6集 短链服务-短链码配置生成库表位实战

简介: 短链服务-短链码配置生成库表位实战

  • 分库位
public class ShardingDBConfig {

    /**
     * 存储数据库位置编号
     */
    private static final List<String> dbPrefixList = new ArrayList<>();

    private static Random random = new Random();

    //配置启用那些库的前缀
    static {
        dbPrefixList.add("0");
        dbPrefixList.add("1");
        dbPrefixList.add("a");
    }


    /**
     * 获取随机的前缀
     * @return
     */
    public static String getRandomDBPrefix(){
        int index = random.nextInt(dbPrefixList.size());
        return dbPrefixList.get(index);
    }



}
  • 分表位
public class ShardingTableConfig {

    /**
     * 存储数据表位置编号
     */
    private static final List<String> tableSuffixList = new ArrayList<>();

    private static Random random = new Random();

    //配置启用那些表的后缀
    static {
        tableSuffixList.add("0");
        tableSuffixList.add("a");
    }


    /**
     * 获取随机的后缀
     * @return
     */
    public static String getRandomTableSuffix(){
        int index = random.nextInt(tableSuffixList.size());
        return tableSuffixList.get(index);
    }



}
  • 短链码配置
String code = ShardingDBConfig.getRandomDBPrefix() + shortLinkCode + ShardingTableConfig.getRandomTablePrefix();
第7集 短链服务-Manager层模块CRUD开发

简介: 短链服务-Manager层模块CRUD开发

  • 代码
public interface ShortLinkManager {


    /**
     * 新增域名
     *
     * @param shortLinkDO
     * @return
     */
    int addShortLink(ShortLinkDO shortLinkDO);


    /**
     * 根据短链码找内容
     *
     * @param shortLinkCode
     * @return
     */
    ShortLinkDO findByShortLinkCode(String shortLinkCode);


    /**
     * 根据短链码和accountNo删除
     *
     * @param shortLinkCode
     * @param accountNo
     * @return
     */
    int del(String shortLinkCode, Long accountNo);


}


@Component
@Slf4j
public class ShortLinkManagerImpl implements ShortLinkManager {

    @Autowired
    private ShortLinkMapper shortLinkMapper;

    @Override
    public int addShortLink(ShortLinkDO shortLinkDO) {
        return shortLinkMapper.insert(shortLinkDO);
    }

    @Override
    public ShortLinkDO findByShortLinkCode(String shortLinkCode) {
        ShortLinkDO shortLinkDO = shortLinkMapper.selectOne(new QueryWrapper<ShortLinkDO>().eq("code", shortLinkCode).eq("del", 0));
        return shortLinkDO;
    }

    /**
     * 逻辑删除
     *
     * @param shortLinkCode
     * @param accountNo
     * @return
     */
    @Override
    public int del(String shortLinkCode, Long accountNo) {
        ShortLinkDO shortLinkDO = new ShortLinkDO();
        shortLinkDO.setDel(1);
        int rows = shortLinkMapper.update(shortLinkDO, new QueryWrapper<ShortLinkDO>()
                .eq("code", shortLinkCode).eq("account_no", accountNo));

        return rows;
    }


}
第8集 短链服务-自定义分库分表策略单元测试实战

简介: 短链服务-自定义分库分表策略单元测试实战

单元测试

  • 保存
 @Autowired
    private ShortLinkManager shortLinkManager;
    /**
     * 保存
     */
    @Test
    public void testSaveShortLink() {

        Random random = new Random();
        //for (int i = 0; i < 10; i++) {
            int num1 = random.nextInt(10);
            int num2 = random.nextInt(10000000);
            int num3 = random.nextInt(10000000);
            String originalUrl = num1 + "xdclass" + num2 + ".net" + num3;
            String shortLinkCode = shortLinkComponent.createShortLinkCode(originalUrl);
            ShortLinkDO shortLinkDO = new ShortLinkDO();
            shortLinkDO.setCode(shortLinkCode);
            shortLinkDO.setAccountNo(Long.valueOf(num3));
            shortLinkDO.setSign(originalUrl);
            shortLinkDO.setDel(0);
            shortLinkManager.addShortLink(shortLinkDO);
        //}

    }
  • 查找
@Test
public void testFind() {

  ShortLinkDO shortLinkDO = shortLinkManager.findByShortLinkCode("03aAg0la");
  log.info(shortLinkDO.toString());

}
第9集 加权负载均衡思想应用-数据库表扩容-数据不均匀问题解决方案

简介: 加权负载均衡思想应用-数据库表扩容-数据不均匀问题解决方案

  • 问题
    • 假如前期分三个库,一个库两个表,项目火爆,数据量激增,进行扩容
    • 增加了新的数据库表位,会导致旧的库表比新的库表数据量多,且容易出现超载情况
image-1661249344299
image-1661249344299
image-1661249350076
image-1661249350076

Nginx加权负载均衡的应用(架构大课)

不同的库表位分配的概率不一样,类似的中间件应用场景有nginx

Nginx常见的负载均衡策略

节点轮询(默认)

weight 权重配置

  • 简介:weight和访问比率成正比,数字越大,分配得到的流量越高
  • 场景:服务器性能差异大的情况使用
upstream lbs {
        server 192.168.159.133:8080 weight=5;
        server 192.168.159.133:8081 weight=10;
}
image-1661249367240
image-1661249367240
  • 加权解决方式(作业)
    • 库表位可以使用对象形式,配置权重,避免数据倾斜、数据集中
    • 编写算法,根据不同的,配置权重,不同的库表位配置不同的权重
    • 加权配置,list重复添加出现的高频的库表位
  • 是不是可以把这个亮点记录下
    • 面试的时候再面试官前面说下项目难点和你的解决方案
    • 你想到的解决方案,方便又清晰,还省服务器资源和避免了问题
      • 业务量超过评估量,分库分表-二次扩容的时候避免数据迁移
      • 不用一次性建立很多个库表,可以动态添加,节省服务器资源
      • 使用加权库表位算法,解决扩容后数据倾斜不均匀问题
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-08-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第十八章 短链服务-业务需求和短链码解决方案讲解
    • 第1集 短链服务介绍和应用场景讲解
      • 第2集 需求出发-带你详细一个短链的生命周期
        • 第3集 短链服务生成短链URL的问题你能想到多少
          • 第4集 短链服务问题解决方案讲解-业务关系+跳转问题
            • 第5集 短链服务问题解决方案讲解-短链码生成解决方案《上》
              • 第6集 【重要】敏感数据+自增ID暴露的商业秘密
                • 第7集 短链服务问题解决方案讲解-短链码生成解决方案《下》
                • 第十九章 短链服务-Murmur哈希算法封装组件
                  • 第1集 Guava框架里面的Murmur哈希算法测试
                    • 第2集 短链生成组件ShortLinkComponent封装
                      • 第3集 组件ShortLinkComponent测试和疑惑解答
                      • 第二十章 短链服务-数据库表建立和业务代码开发
                        • 第1集 数据库表模型讲解-短链分组和短链
                          • 第2集 MybatisPlus逆向工具生成短链服务相关java对象
                            • 第3集 同学遇到的坑-配置文件修改-yml转properties
                              • 第4集 短链分组管理-CURD接口开发实战《上》
                                • 第5集 短链分组管理-CURD接口开发实战《下》
                                  • 第6集 短链分组管理-水平分库分表配置实战《青铜玩法》
                                  • 第二十一章 短链服务分库分表-如何做到扩容免数据迁移《黄金玩法》
                                    • 第1集 短链服务-ShortLink分库分表解决方案讲解《青铜》
                                      • 第2集 短链服务-分库分表扩容免数据迁移解决方案讲解《黄金玩法》
                                        • 第3集 短链服务-分库分表相关库表建立
                                          • 第4集 短链服务水平分库分表实战-标准分片策略-精准分片算法《上》
                                            • 第5集 短链服务水平分库分表实战-标准分片策略-精准分片算法《下》
                                              • 第6集 短链服务-短链码配置生成库表位实战
                                                • 第7集 短链服务-Manager层模块CRUD开发
                                                  • 第8集 短链服务-自定义分库分表策略单元测试实战
                                                    • 第9集 加权负载均衡思想应用-数据库表扩容-数据不均匀问题解决方案
                                                    相关产品与服务
                                                    数据库
                                                    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                                                    领券
                                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档