当前位置: 首页 > news >正文

thinkphp 做分布式服务+读写分离+分库分表(分区)(后续接着写)

thinkphp 做分布式服务+读写分离+分库分表(分区)

    • 引言 thinkphp* 大道至简
    • 一、分库分表
      • 分表
        • php 分库分表hash算法
        • 0、分表的方法(thinkphp)
        • 1、ThinkPHP6 业务分表之一:UID 发号器
        • 2、ThinkPHP6 业务分表之二:用户
    • 其他杂项
      • 1亿条数据在PHP中实现Mysql数据库分表100张

引言 thinkphp* 大道至简

一、分库分表

分表

分表分库一般分垂直和水平,垂直是指感觉业务来进行库的拆分,比如专门的用户库或者订单库这样子,但垂直还是无法解决单表数据量过大导致的性能会差的问题(这里可能会和上面矛盾,网上多数指的是 2000W 就会影响,但好像没有多少人谈过他们的表结构情况)。水平分指的是某一个表,里面的数据量非常大,我们按照一定的规则来进行一个拆分分流,比如把用户的数据由一直存放在用户表,变为可能这条数据是在用户1号表或者2号表这样子。规则可能是 范围(range)或者哈希(hash),也不知道我喜欢的取模算不算哈希。分了其实会带来一些问题的复杂性,比如分库那如何确保多库事务性的一致性、分布式锁等等很多,然后还有之前我们的 join 查询,现在可能就无法使用呢。

php 分库分表hash算法

app/common.php 公共方法定义
$userid 也可以用下面的uid 发号器定义,通过哈希来就算出表名称

//哈希分表function get_hash_table($table, $userid) {$str = crc32($userid);if ($str < 0) {$hash = "0" . substr(abs($str), 0, 1);} else {$hash = substr($str, 0, 2);}return $table . "_" . $hash;}

控制器调用计算表名

public function index() {echo $table=get_hash_table('message', '18991').'<br>';echo $table=get_hash_table('message', '18993').'<br>';echo $table=get_hash_table('message', '18994').'<br>';
}
0、分表的方法(thinkphp)
public function getPartitionTableName($data=array()) {// 对数据表进行分区if(isset($data[$this->partition['field']])) {$field   =   $data[$this->partition['field']];switch($this->partition['type']) {case 'id':// 按照id范围分表$step    =   $this->partition['expr'];$seq    =   floor($field / $step)+1;break;case 'year':// 按照年份分表if(!is_numeric($field)) {$field   =   strtotime($field);}$seq    =   date('Y',$field)-$this->partition['expr']+1;break;case 'mod':// 按照id的模数分表$seq    =   ($field % $this->partition['num'])+1;break;case 'md5':// 按照md5的序列分表$seq    =   (ord(substr(md5($field),0,1)) % $this->partition['num'])+1;break;default :if(function_exists($this->partition['type'])) {// 支持指定函数哈希$fun    =   $this->partition['type'];$seq    =   (ord(substr($fun($field),0,1)) % $this->partition['num'])+1;}else{// 按照字段的首字母的值分表$seq    =   (ord($field{0}) % $this->partition['num'])+1;}}return $this->getTableName().'_'.$seq;}else{// 当设置的分表字段不在查询条件或者数据中// 进行联合查询,必须设定 partition['num']$tableName  =   array();for($i=0;$i<$this->partition['num'];$i++)$tableName[] = 'SELECT * FROM '.$this->getTableName().'_'.($i+1);$tableName = '( '.implode(" UNION ",$tableName).') AS '.$this->name;return $tableName;}
}
1、ThinkPHP6 业务分表之一:UID 发号器

我们现在假设项目是新成立的,暂时没有一个技术债。目前我们要先规划一个用户表,打算划分 16 个表,按照取模的方式来查询。最先可能我们要考虑如何定义 UID 的问题,不过对我们 PHPer 来说不是什么难事,毕竟我们基本都不用 UUID 来做 UID 的,占用的空间会比较多,不利于索引。

但是不用 UUID ,选择了 INT 来做 UID,那我们要如何确保它的连续性和唯一性呢?业内常用的可能是雪花算法,但我选择自己写一个简易的发号器。

发号器需要加东西,然后取东西,我们可以利用 Redis List 来很好的实现我们需要的先进先出功能。通过一个命令或者说脚本,我们定时往列表中填上自增的 ID,然后在注册流程中来取最前面的。
在这里插入图片描述
代码层面
app/common.php 公共方法定义获取redis 的值

if(!function_exists('get_redis')) {function get_redis() {return new \Predis\Client('tcp://IP:端口', ['parameters' => ['password' => '密码',],]);}
}

定义一个发号器函数
app/command/GenerateUID.php

<?php
declare (strict_types = 1);namespace app\command;use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;class GenerateUID extends Command
{protected $redis;/** 发号器列表 键** @var string*/protected $cache_key = 'generate:uid';/** 锁 键** @var string*/protected $lock_key = 'generate:uid_lock';/** 发号器列表最大容量,默认为 500000** @var int*/protected $max_capacity = 5E5;public function __construct(){$this->redis = get_redis();parent::__construct();}protected function configure(){// 指令配置$this->setName('generate:uid')->setDescription('生成 UID');}protected function execute(Input $input, Output $output){$current_capacity = $this->get_list_length();// 计算发号器需要增加的数量$append_capacity = $this->max_capacity - $current_capacity;$uid_max = $this->get_uid_max();$output->writeln('当前最大UID:' . $uid_max);$output->writeln('当前剩余容量:' . $current_capacity);$output->writeln('最大存储容量:' . $this->max_capacity);$output->writeln('需要追加容量:' . $append_capacity);// 如果不需要增加则结束if($append_capacity === 0) {return;}$data = [];for($i = 1; $i <= $append_capacity; $i++) {$data[] = $uid_max + $i;}// 把需要加的数据进行分块,方便快速追加$data = array_chunk($data, 1000);// 加锁$lock = $this->redis->executeRaw(['SET',$this->lock_key,1,'EX',10 * 60,'NX',]);if($lock !== 'OK') {$output->writeln('获取锁失败');return;}try {foreach ($data as $item) {$this->redis->rpush($this->cache_key, $item);}} catch (\Exception $e) {$output->error($e->getMessage());} finally {// 释放锁$this->redis->del($this->lock_key);}}/** 获取发号器列表的长度** @return int*/protected function get_list_length() :int{return $this->redis->llen($this->cache_key);}/** 获取当前最大的 UID** @return int*/protected function get_uid_max() :int{$value = (int) $this->redis->lindex($this->cache_key, -1);if($value) {return $value;}return 0;}
}

config/console.php 定义一个打印函数类

<?php
return [// 指令定义'commands' => [...'generate:uid' => 'app\command\GenerateUID',],
];

执行命令

$ php think generate:uid
当前最大UID:0
当前剩余容量:0
最大存储容量:500000
需要追加容量:500000

2、ThinkPHP6 业务分表之二:用户

上一篇我们将了 UID 的发号器,那这一篇我们将要去实现用户的注册入库和简单的查询。

首先我们要实现数据表的识别。获取表名称
app/common.php

if(!function_exists('table_name')) {/** 获取表名称** @param string $name 表名* @param int|null $uid UID* @return string*/function table_name(string $name, ?int $uid = null) {$support_table = ['users' => 16, // 表名 => 分表数];if(!isset($support_table[$name])) {return $name;}// 如果没有传递 UID,那则需要调用其他方法来获取 UIDif(is_null($uid)) {$uid = (int) 1;}if((int) $uid === 0) {throw new \Exception('UID 值异常');}// 取 UID 和 分表数的模,值转化为小写十六进制return sprintf('%s_%x', $name, $uid % $support_table[$name]);}
}

执行写入操作
app/controller/Auth.php

<?php
namespace app\controller;use app\BaseController;
use think\facade\Db;
use think\helper\Str;class Auth extends BaseController
{/** 注册接口*/public function register(){$redis = get_redis();// 获取最左的值$uid = $redis->lpop('generate:uid');// 为空说明列表已经没内容了if(is_null($uid)) {return '无法获取 UID';}// 获取表名$table_name = table_name('users', $uid);// 插入数据Db::table($table_name)->insert(['id' => $uid,'nickname' => '随机生成' . Str::random(),]);return '注册成功';}
}

其他杂项

1亿条数据在PHP中实现Mysql数据库分表100张

当数据量猛增的时候,大家都会选择库表散列等等方式去优化数据读写速度。笔者做了一个简单的尝试,1亿条数据,分100张表。具体实现过程如下:
首先创建100张表:

$i=0;
while($i<=99){
echo "$newNumber \r\n";
$sql="CREATE TABLE `code_".$i."` (`full_code` char(10) NOT NULL,`create_time` int(10) unsigned NOT NULL,PRIMARY KEY  (`full_code`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8";
mysql_query($sql);
$i++;

下面说一下我的分表规则,full_code作为主键,我们对full_code做hash
函数如下:

$table_name=get_hash_table('code',$full_code);
function get_hash_table($table,$code,$s=100){
$hash = sprintf("%u", crc32($code));
echo $hash;
$hash1 = intval(fmod($hash, $s));return $table."_".$hash1;
}

这样插入数据前通过get_hash_table获取数据存放的表名。
最后我们使用merge存储引擎来实现一张完整的code表

1 CREATE TABLE IF NOT EXISTS code (
2 full_code char(10) NOT NULL,
3 create_time int(10) unsigned NOT NULL,
4 INDEX(full_code)
5 ) TYPE=MERGE UNION=(code_0,code_1,code_2…) INSERT_METHOD=LAST ;

这样我们通过select * from code就可以得到所有的full_code数据了。

相关文章:

thinkphp 做分布式服务+读写分离+分库分表(分区)(后续接着写)

thinkphp 做分布式服务读写分离分库分表&#xff08;分区&#xff09; 引言 thinkphp* 大道至简一、分库分表分表php 分库分表hash算法0、分表的方法&#xff08;thinkphp&#xff09;1、ThinkPHP6 业务分表之一&#xff1a;UID 发号器2、ThinkPHP6 业务分表之二&#xff1a;用…...

webpack的使用

将js读取的目录改成读内存中的main.js&#xff0c;否则不会生效 为了 将index.html在打开首页的时候就能自动显示&#xff0c;就需要引入插件 指定开发环境运行的命令&#xff1a; dev&#xff1a;开发环境&#xff0c;build生产环境...

MATLAB智能优化算法-学习笔记(3)——大规模邻域搜索算法求解旅行商问题【过程+代码】

一、问题描述 旅行商问题(TSP, Traveling Salesman Problem)是组合优化中的经典问题之一。给定一组城市和每对城市之间的距离,要求找到一条最短的路径,使旅行商从某个城市出发,访问每个城市一次并最终回到出发点。TSP问题广泛应用于物流配送、工厂调度、芯片制造等领域。…...

货币单位换算 - 华为OD统一考试(E卷)

2024华为OD机试&#xff08;E卷D卷&#xff09;最新题库【超值优惠】Java/Python/C合集 题目描述 记账本上记录了若干条多国货币金额&#xff0c;需要转换成人民币分(fen)&#xff0c;汇总后输出。 每行记录一条金额&#xff0c;金额带有货币单位&#xff0c;格式为数字单位&…...

95、k8s之rancher可视化

一、ranker 图形化界面 图形化界面进行k8s集群的管理 rancher自带监控----普罗米修斯 [rootmaster01 opt]# docker load -i rancher.tar ##所有节点 [rootmaster01 opt]# docker pull rancher/rancher:v2.5.7 ##主节点[rootmaster01 opt]# vim /etc/docker/daemon.jso…...

简单生活的快乐

小明经常会被问到一个问题&#xff1a;为什么他那么有钱却选择过一种简单、谦逊的生活。先从小明的早年经历说起吧&#xff0c;大概是他六到十三岁的时候&#xff0c;物质对他来说是非常重要的。他记得当妈妈给他买了一双昂贵的鞋子时&#xff0c;他特别兴奋&#xff0c;喜欢向…...

【JAVA开源】基于Vue和SpringBoot的在线文档管理系统

本文项目编号 T 038 &#xff0c;文末自助获取源码 \color{red}{T038&#xff0c;文末自助获取源码} T038&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…...

大数据新视界 --大数据大厂之数据驱动决策:如何利用大数据提升企业竞争力

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

【Linux】生产者消费者模型:基于阻塞队列,使用互斥锁和条件变量维护互斥与同步关系

目录 一、什么是生产者消费者模型 二、为什么要引入生产者消费者模型&#xff1f; 三、详解生产者消费者模型 ​编辑 生产者和生产者、消费者和消费者、生产者和消费者&#xff0c;它们之间为什么会存在互斥关系&#xff1f; 生产者和消费者之间为什么会存在同步关系&…...

多层感知机paddle

多层感知机——paddle部分 本文部分为paddle框架以及部分理论分析&#xff0c;torch框架对应代码可见多层感知机 import paddle print("paddle version:",paddle.__version__)paddle version: 2.6.1多层感知机&#xff08;MLP&#xff0c;也称为神经网络&#xff0…...

linux-网络管理-网络服务管理 17 / 100

Linux 网络管理&#xff1a;网络服务管理 一、概述 在 Linux 系统中&#xff0c;网络服务管理是系统管理中的重要组成部分。网络服务通常涉及到多种协议、服务和工具&#xff0c;用于确保服务器与客户端、局域网与广域网、以及不同系统之间的通信畅通。Linux 提供了强大的工具…...

Docker上安装mysql

获取 MySQL 镜像 获取镜像。使用以下命令来拉取镜像&#xff1a; 1docker pull mysql:latest 这里拉取的是最新版本的 MySQL 镜像。你也可以指定特定版本&#xff0c;例如&#xff1a; 1docker pull mysql:8.0 运行 MySQL 容器 运行 MySQL 容器时&#xff0c;你需要指定一些…...

【秋招笔试-支持在线评测】8.28华为秋招(已改编)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 华为专栏传送🚪 -> 🧷华为春秋招笔试 目前今年秋招的笔…...

基于python上门维修预约服务数据分析系统

目录 技术栈和环境说明解决的思路具体实现截图python语言框架介绍技术路线性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示操作可行性详细视频演示源码获取 技术栈和环境说明 结合用户的使用需求&#xff0c;本系统采用运用较为广…...

React基础教程(10):React Hooks

9.1 使用hooks理由 高阶组件为了复用,导致代码层级复杂。生命周期的复杂。写成函数组件,无状态组件,因为需要状态,又写成了class,成本高9.2 useState(保存组件状态) const [state, setState] = useState(initialState);案例:点击按钮修改name...

JVM 调优篇9 调优案例6- cpu使用过载解决办法【超赞】

一 cpu过载说明 1.1 背景说明 如果线程死锁,那么线程一直在占用CPU,这样就会导致CPU一直处于一个比较高的占用率。 1.2 代码 模拟一个死锁的代码 public class JstackDeadLockDemo {/*** 必须有两个可以被加锁的对象才能产生死锁,只有一个不会产生死锁问题*/private f…...

Spring8-事务

目录 JdbcTemplate 声明式事务 事务 概述 特性&#xff08;ACID&#xff09; 编程式事务 声明式事务 基于注解的声明式事务 Transactional注解标识的位置 事务属性&#xff1a;只读 事务属性&#xff1a;超时 事务属性&#xff1a;隔离级别 事务属性&#xff1a;传…...

在Python中,类是用于定义对象的蓝图或模板,而对象则是根据类创建的具体实例

当然&#xff0c;我可以为您演示类与对象的基本概念和它们之间的关系。在Python中&#xff0c;类是用于定义对象的蓝图或模板&#xff0c;而对象则是根据类创建的具体实例。 下面是一个简单的Python程序&#xff0c;它定义了一个Car类&#xff0c;该类具有一些属性和方法&…...

【小波去噪】【matlab】基于小波分析的一维信号滤波(对照组:中值滤波、均值滤波、高斯滤波)

链接1-傅里叶变换 链接2-傅立叶分析和小波分析间的关系 链接3-小波变换&#xff08;wavelet transform&#xff09;的通俗解释 链接4-小波基的选择 1.示例代码 function main_wavelet clc clear close all warning off %% 1.信号生成 time_length 10;%总时长&#xff0c;秒 …...

CentOS 7官方源停服,配置本机光盘yum源

1、挂载系统光盘 mkdir /mnt/iso mount -o loop /tools/CentOS-7-x86_64-DVD-1810.iso /mnt/iso cd /mnt/iso/Packages/ rpm -ivh /mnt/iso/Packages/yum-utils-1.1.31-50.el7.noarch.rpm(图形界面安装&#xff0c;默契已安装&#xff09; 如安装yum-utils依赖错误&#x…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...