mysql高可用分库分表ShardingSphere之Sharding-proxy

2023-11-18

一、ShardingSphere

1.1、官网地址说明

官网地址: https://shardingsphere.apache.org/index_zh.html

本文采用Sharding-proxy代理方式进行分库分表

Sharding-proxy官网手册地址

在这里插入图片描述

1.2、为什么分库分表

  1. 单纯的主从模式,无法保证mysql的高可用
  2. 在单表大数据的情况下,会让mysql的检索性能大幅度下降
  3. 分库分表会减轻压力,提高检索速度
  4. 分库分表,读写分离

架构图:


二、官网整合说明

1.1、下载sharding-proxy

  1. 我用的版本是4.0.0
  2. 官网目前最新版本5.1.0

Sharding-Proxy下载地址
在这里插入图片描述
在这里插入图片描述

1.2、sharding-proxy集成注册中心

  1. 这个默认使用zk
  2. 这个就看文档搞就可用了
    在这里插入图片描述

1.3、查看配置手册

在这里插入图片描述

1.3.1、官网数据分片说明

Sharding-Proxy支持多逻辑数据源每个以config-前缀命名的yaml配置文件,即为一个逻辑数据源。以下是config-xxx.yaml的配置配置示例。

其他的也一样,看官网

官网配置说明:

schemaName: sharding_db

dataSources: #定义数据源
  ds0: #数据源1
    url: jdbc:postgresql://localhost:5432/ds0
    username: root
    password: 
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 65
  ds1: #数据源2
    url: jdbc:postgresql://localhost:5432/ds1
    username: root
    password: 
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 65

shardingRule: #配置分片规则
  tables:
    t_order: #需要分片的表-订单表
      # 真实数据节点。 ds${0..1}.t_order${0..1} 表示 分成2个库ds0,ds1,2张表t_order0,t_order1
      actualDataNodes: ds${0..1}.t_order${0..1} 
      databaseStrategy:#数据库的分库策略
        inline:
          shardingColumn: user_id #按 user_id 这一列来分
          algorithmExpression: ds${user_id % 2} #指定算法 user_id对2取余,余数0取ds0库,余数1取ds1库
      tableStrategy: #分表策略
        inline:
          shardingColumn: order_id #用order_id 这个列来分
          algorithmExpression: t_order${order_id % 2} # 指定算法
      keyGenerator: #id自动生成
        type: SNOWFLAKE # 雪花算法
        column: order_id #雪花算法的id存在order_id
        
    t_order_item: #需要分片的表-订单项表
      actualDataNodes: ds${0..1}.t_order_item${0..1}
      databaseStrategy:
        inline:
          shardingColumn: user_id
          algorithmExpression: ds${user_id % 2}
      tableStrategy:
        inline:
          shardingColumn: order_id
          algorithmExpression: t_order_item${order_id % 2}
      keyGenerator:
        type: SNOWFLAKE
        column: order_item_id
        
  bindingTables:#指定关联表
    - t_order,t_order_item
  defaultTableStrategy: #默认分表规则
    none:

1.3.2、配置文件说明

在这里插入图片描述

三、开始整合

1. 引入mysql的驱动

  1. 4.0版本需要引入
  2. 5.0版本不需要了,看配置文件的注解就行

如图:
在这里插入图片描述
在这里插入图片描述

2. 配置认证授权信息 server.yaml

server.yaml

#服务治理模块的配置
#orchestration:
#  name: orchestration_ds
#  overwrite: true
#  registry:
#    type: zookeeper
#    serverLists: localhost:2181
#    namespace: orchestration
#

#配置2个用户  用户1[账号密码都是:root]   用户2[账号密码都是:sharding]
authentication:
  users: 
    root:
      password: root 
    sharding:
      password: sharding 
      #用户sharding的权限只能操作 sharding_db 
      authorizedSchemas: sharding_db 

#配置属性 线程数、sql打印、最大连接...     
props:
#  max.connections.size.per.query: 1
  acceptor.size: 16 
  executor.size: 16  
#  proxy.frontend.flush.threshold: 128  # The default value is 128.
#    # LOCAL: Proxy will run with LOCAL transaction.
#    # XA: Proxy will run with XA transaction.
#    # BASE: Proxy will run with B.A.S.E transaction.
#  proxy.transaction.type: LOCAL
#  proxy.opentracing.enabled: false
#  query.with.cipher.column: true
  sql.show: false

3. 配置分库分表 config-sharding.yaml

config-sharding.yaml

######################################################################################################
#
# If you want to connect to MySQL, you should manually copy MySQL driver to lib directory.
#
######################################################################################################

#数据库名称-随便叫【前提环境MySQL主从同步的配置已经搞好了】
schemaName: sharding_db
#配置数据源
dataSources:
  ds_0: #第一个主mysql,连接 demo_ds_0库
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50 
  ds_1: #第2个主mysql[因为没搞第二个主,就连同一个主了] 连接 demo_ds_1 库
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
#==============================================

#定义规则
shardingRule:
  tables: 
    #订单表
    t_order: 
      # ds_${0..1}和上面配置的数据源(ds_0,ds_1)对应。表划分成t_order_1、t_order_2 ,一个库里面2张表
      actualDataNodes: ds_${0..1}.t_order_${0..1}
      # 分表策略
      tableStrategy:
        inline:
          # 用order_id来分表
          shardingColumn: order_id
          # 算法->求余
          algorithmExpression: t_order_${order_id % 2}
      # order_id生成的算法,用雪花算法
      keyGenerator:
        type: SNOWFLAKE
        column: order_id
        
#-------------------------     
    #订单项表
    t_order_item:
      #分成2个库,2张表
      actualDataNodes: ds_${0..1}.t_order_item_${0..1}
      #指定分表策略
      tableStrategy:
        inline:
          #用order_id来分
          shardingColumn: order_id
          #算法-->求余
          algorithmExpression: t_order_item_${order_id % 2}
      # order_item_id 自动生成用雪花算法
      keyGenerator:
        type: SNOWFLAKE
        column: order_item_id
#-------------------------  

  #绑定表(表有关系)-好处:省得跨库找,不会产生笛卡儿积,速度快,效率高
  bindingTables:
    - t_order,t_order_item
#-------------------------

   
  #数据库策略-分库策略====>流程:先用user_id进行了分库。然后在根据order_id来分表
  defaultDatabaseStrategy:
    inline:
      # 用user_id 列来分
      shardingColumn: user_id
      # 算法 -->求余数
      algorithmExpression: ds_${user_id % 2}
      
  #默认的分表策略。共用部分
  defaultTableStrategy:
    none:

4. 配置读写分离 config-master_slave.yaml

config-master_slave.yaml

######################################################################################################
#
# If you want to connect to MySQL, you should manually copy MySQL driver to lib directory.
#
######################################################################################################

#这个名称在配置里面必须唯一,不能相同
schemaName: sharding_db_1
#配置数据源
dataSources:
  #第一个库的主从--连接demo_ds_0库
  #主节点数据源
  master_0_ds:
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
  #从节点数据源
  slave_0_ds:
    url: jdbc:mysql://192.168.56.10:3317/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
#--------------------------------- 
 
  #第2个库的主从--连接demo_ds_1库
  #主节点数据源
  master_1_ds:
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
  #从节点数据源
  slave_1_ds:
    url: jdbc:mysql://192.168.56.10:3317/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50

#配置数据库的主从规则  
shardingRule: 
  masterSlaveRules:
    ms_ds0:
      masterDataSourceName: master_0_ds
      slaveDataSourceNames:
        - slave_0_ds
      loadBalanceAlgorithmType: ROUND_ROBIN
    ms_ds1:
      masterDataSourceName: master_1_ds
      slaveDataSourceNames: 
        - slave_1_ds
      loadBalanceAlgorithmType: ROUND_ROBIN

5、mysql的主从同步加入demo_ds_0,demo_ds_1库

mysql主从同步看==> mysql集群主从复制1主多从 (一)

停止mysql容器

docker stop mysql-master01 mysql-slaver01

编辑主mysql文件

#切换到数据挂载目录
cd /mydata/mysql/master01/conf/

# 编辑
vi my.cnf

# 内容
#Sharding-proxy测试的库
binlog-do-db=demo_ds_0
binlog-do-db=demo_ds_1

编辑从mysql文件

#切换到数据挂载目录
cd /mydata/mysql/master01/conf/

# 编辑
vi my.cnf

# 内容
#Sharding-proxy测试的库
binlog-do-db=demo_ds_0
binlog-do-db=demo_ds_1

启动mysql容器

#启动
docker start mysql-master01  mysql-slaver01 

#查看
docker ps

如图:
在这里插入图片描述
在这里插入图片描述

6、主mysql创建出demo_ds_0,demo_ds_1库

如图:
在这里插入图片描述

7、启动Sharding-proxy

在这里插入图片描述
指定端口启动:
在这里插入图片描述

启动成功:
在这里插入图片描述

8、navicat连接Sharding-proxy操作数据库

  1. 端口上面指定的13777
  2. 账号的server.yaml里面配置的
  3. 账号root
  4. 密码root

这边不能使用navicat15来连接不然会报错

如图:
在这里插入图片描述

在这里插入图片描述

8.1、建表测试

运行sql-刷新

#订单
CREATE TABLE `t_order` (
`order_id` bigint(20) NOT NULL, `user_id` int(11) NOT NULL, `status` varchar(50) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

#订单项
CREATE TABLE `t_order_item` (
`order_item_id` bigint(20) NOT NULL, `order_id` bigint(20) NOT NULL, `user_id` int(11) NOT NULL, `content` varchar(255) COLLATE utf8_bin DEFAULT NULL, `status` varchar(50) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

连接Sharding-proxy后台会屏蔽0.1这些分成的库

如图:
在这里插入图片描述
在这里插入图片描述

8.2、插入数据测试

流程 根据user_id取余,选择库,在根据,生成的order_id取余选择表

在这里插入图片描述
效果:
在这里插入图片描述
会发现数据自动分到了2个库里面的不同表
这个是根据我们指定的规则,取余数计算出来的

如图:
在这里插入图片描述

在这里插入图片描述


四、mysql集群的高可用

  1. 不推荐使用多主模式选举,例如MHA 他是小日子开发的…
  2. 使用主从复制+分库分表(多分库就可以。数据源多配置几个)
  3. 高可用也可以配置上 1个keeplived+2个Sharding-proxy来保证高可用
  4. mysql本身就很稳定,除非你超负载了
  5. 多主模式带来的问题,个人感觉会更大,个人不推荐使用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql高可用分库分表ShardingSphere之Sharding-proxy 的相关文章

  • 在 OS X 10.7 中找不到 Mysql 命令

    我无法让我的 mysql 在 os x 10 7 上启动 它位于 usr local mysql bin mysql 当我输入时 我得到命令未找到mysql version在终端中 我试过这个无法从 mac 命令行访问 mysql http
  • 导入 CSV 以更新表中的行

    大约有 26K 个产品 帖子 每个产品都有如下元值 post id 列是数据库中的产品 ID sku meta key 是每个产品的唯一 ID 我收到了一个新的 CSV 文件 该文件更新了每个产品的 sale price meta key
  • 使用另一个表中的数据查找并替换 MySQL 中的字符串

    我有两个 MySQL 表 我想使用另一个表中的数据查找和替换一个表中的文本字符串 Table texts messages thx guys i think u r great thx again u rock Table dictiona
  • MySql如何通过过滤多列来限制多个数字?

    我想从数据库中获取 4 个不同类别的 50 个问题 我想要 4 个不同类别中每个类别的不同数量的问题 我的结果集必须包含第一类 12 个问题 第二类 20 个问题 第三类 10 个问题和第四类 8 个问题 我的问题表中总共有 50 个问题
  • 不唯一的表/别名

    因此 我尝试使用多个联接来运行此查询 以获得我想要的精确行 但我不断收到此错误 不唯一的表 别名 ss prices 我正在运行的查询 select ss accounts id ss accounts bot acc id ss acco
  • ASP.NET API:尚未为此 DbContext 配置数据库提供程序

    我正在尝试从我的 Net Core API 项目连接到 MySql 数据库 这是我的上下文类 public class MyContext DbContext public MyContext public MyContext DbCont
  • UNIX时间记录时区吗?

    我想问一下UNIX时间 UNIX时间是否记录时区 我将托管从美国芝加哥移至 JST 问题是我的整个 MySQL 数据库都有 UNIX 时间 芝加哥 美国时区 的记录 我有一个 PHP 代码来显示之前的时间 例如 3 天前 昨天等 当我搬到新
  • 为 Mariadb 安装连接器 C

    所以 我想使用 Mariadb 有一个连接器 C https downloads mariadb org connector c https downloads mariadb org connector c 我该如何安装它 坦白说 它的文
  • 使用 EXPLAIN 进行 MYSQL 存储过程调用

    如何分析和使用 EXPLAIN 来调用我的存储过程 我需要优化查询时间 但是似乎没有地方可以执行 EXPLAIN 调用 proc name 你可以试试 set profiling 1 call proc name show profiles
  • MySQL 5左连接未知列

    我有以下查询在 mysql 4 1 中工作 但在 5 0 中不起作用 SELECT FROM email e event email ee LEFT JOIN member m on m email e email WHERE ee ema
  • 选择MySql表数据放入数组中

    我尝试从 mysql 捕获数据并将它们全部放入数组中 认为 users table id name code 1 gorge 2132 2 flix ksd02 3 jasmen skaod2 sql mysql query select
  • 在 MySQL 中分割逗号分隔值

    我正在尝试将字符串中以逗号分隔的 值拆分为多列 样本数据 COL1 COL2 COL3 000002 000003 000042 09 31 51 007 004 007 预期输出 Pno Cno Sno 000002 09 007 000
  • 如何使用实体框架设置连接字符串

    我将 EF6 与 MySQL 结合使用 并有一个用于多个数据库的模型 我希望能够在我的表单中设置连接设置 如何以编程方式设置模型的连接字符串 你应该使用EntityConnectionFactory这就是您所需要的 public strin
  • RMySQL fetch - 找不到继承的方法

    使用 RMySQL 我想将数据从数据库加载到 R 中的数据帧中 为此 我使用以下代码 R连接数据库 con lt dbConnect MySQL user root password password dbname prediction h
  • PMA 4.5.2.0 file_exists():open_basedir 限制生效

    从 PPA 在我的 Ubuntu 服务器上安装 phpMyAdmin 后 https launchpad net nijel archive ubuntu phpmyadmin https launchpad net nijel archi
  • Sql:计算随时间的增长

    我几周前发布了这个问题 但我认为我没有清楚地提出这个问题 因为我得到的答案不是我想要的 我认为最好重新开始 我正在尝试查询数据库以检索一段时间内唯一条目的数量 数据看起来像这样 Day UserID 1 A 1 B 2 B 3 A 4 B
  • SQL Server 相当于 MySQL 的 USING

    在 MySQL 中 当您连接不同表中具有相同名称的列时 可以在连接中使用关键字 USING 例如 这些查询产生相同的结果 SELECT FROM user INNER JOIN perm USING uid SELECT FROM user
  • Laravel Group By 和 Order By 不起作用

    我尝试制作一个Laravel 5 8项目 项目中的数据是这样的 id purch name prcvalue 1 10234 Nabila 100 2 10234 Nadeera 450 3 10234 Nabila 540 4 10234
  • Clojure MySQL 语法错误异常(“[...] 靠近 '???????????????' [...]”)

    除了建立连接之外 我在使用 clojure contrib sql 做任何事情时都遇到困难 我有一个 mysqld 在 localhost 3306 上运行 数据库名为clj db 用户 clj user localhost 和密码 clj
  • 让 Prometheus 发送 SQL 查询

    我正在尝试使用普罗米修斯 https prometheus io 监视我的 MySQL 数据库 但似乎找不到添加 SQL 查询的区域 例如 我想运行一个返回值的 SQL 查询 然后将该值添加到图表中 发送警报 有没有办法让 Promethe

随机推荐

  • 23种设计模式之装饰模式

    装饰模式 一个简陋的房子 它可以让人在里面居住 为人遮风避雨 但如果给它进行装修 那么它的居住环境就更加宜人了 程序中的对象也与房子十分类似 首先有一个相当于 房子 的对象 然后经过不断装饰 不断对其增加功能 它就变成了使用功能更加强大的对
  • Unity Cinemachine插件学习笔记,实现单目标和多目标之间切换

    Cinemachine在2017版中正式加入 结合Timeline可以轻松的制作出一下相机动画 相比Unity自带的标准相机 这个Cinemachine插件可操作的变量更多 不同虚拟相机 用来控制相机的 可以平滑转换等 具体可以参考上篇 U
  • pytorch:如何修改加载了预训练权重的模型的输入或输出--(原权重文件修改参数)

    在使用pytorch的过程中 我们往往会使用官方发布的预训练模型 并在此基础上训练自己的模型 为了适配训练数据 有时候需要局部修改这类预训练模型的结构 本文将分别以修改输入的通道数和输出的分类数为例 讲解一种通用的方法来修练模型的结构 加载
  • 图像去模糊:MSSNet 模型详解

    本内容主要介绍实现单图像去模糊的 MSSNet 模型 论文 MSSNet Multi Scale Stage Network for Single Image Deblurring 代码 官方 https github com kky7 M
  • 什么是 DevSecOps?2022 年的定义、流程、框架和最佳实践

    DevSecOps 是一套实用且面向目标的方法 用于确保系统安全 DevSecOps 被定义为通过与 IT 安全团队 软件开发人员和运营团队合作 在标准 DevOps 周期中建立关键安全原则的过程 以下是对 2022 年 DevSecOps
  • 基于单片机的无线数据传输系统设计

    基于单片机的无线数据传输系统设计 类别 电子综合 1 引 言 随着计算机 通信和无线技术的逐步融合 在传统的有线通信的基础上 无线通信技术应运而生 他具有快捷 方便 可移动和安全等优势 所以广泛应用到遥控玩具 汽车电子 环境监测和电气自动化
  • 使用java关键字编写代码

    使用java关键字编写代码 java的关键字 java的基本数据类型 Java是一种强类型语言 必须为每一个变量声明一种类型 Java共包含8中基本类型 其中4种整型 2种浮点型 1种用于表示Unicode编码的字符单元的字符类型char和
  • Oracle VM VirtualBox做好虚拟硬盘后,如何进一步更改虚拟硬盘的大小

    以管理员身份打开 命令提示符窗口 然后利用命令cd进入Oracle VM VirtualBox安装目录 如下图 我进入了Oracle VM VirtualBox安装目录 D Program Files Oracle VirtualBox 然
  • 隐藏此电脑的视频,图片,文档,下载,音乐和3D对象

    此电脑美化 我们平常使用的资源管理器界面 3D 对象 视频 图片这些我们不需要的东西给占据 作为一个有强迫症的人我决定对其进行修改 最终结果如下如所示 网上普遍叫的方法是通过修改注册表文件进行修改 比较好的文章有 Win10删除资源管理器
  • moviepy音视频剪辑:视频半自动追踪人脸打马赛克

    一 引言 在 moviepy1 03音视频剪辑 使用manual tracking和headblur实现追踪人脸打马赛克 介绍了使用手动跟踪跟踪人脸移动轨迹和使用headblur对人脸进行打马赛克 实际上 moviepy除了使用manual
  • windows服务启动失败解决流程

    最近遇到windows服务启动失败的情况 网上查阅了一下相关的解决方式 顺便记录一下解决的一般流程和方式 一般是软件的配置文件出现问题 先检查配置文件是否有问题 例如没有符合yml格式 不可使用tab键而是空格键 等细节问题 1 查看相关应
  • C++const限定符

    最近通过网络资料复习const 后通过跟专业书籍对比 发现网络上很多都存在一些错误 于是在此做个笔记 1 const定义常量 一旦创建后其值就不能再改变 所以其必须初始化 若用表达式初始化 那么会在运行时初始化 若用值初始化 则在编译阶段初
  • 完美解决sqlalchemy.exc.ObjectNotExecutableError: Not an executable object

    报错的程序如下 from sqlalchemy import create engine import pandas as pd engine create engine mysql pymysql root 123456 localhos
  • 双极性正弦脉宽调制(双极性SPWM)介绍及MATLAB仿真验证

    前言 本文介绍单相全桥逆变电路双极性正弦脉冲宽度调制 双极性SPWM 并用MATLAB仿真验证 并且通过对比逆变器滤波前后效果 突出了SPWM谐波高频化 便于滤除的显著特点 希望本文对大家有帮助 文末有仿真模型代码 有需要自取 目录 前言
  • PM2常用命令

    安装pm2 npm install g pm2 1 启动 1 pm2 start app js 2 pm2 start app js name my api my api为PM2进程名称 3 pm2 start app js f name
  • chatgpt赋能python:如何用Python求和

    如何用Python求和 Python是一种高级编程语言 最初设计用于简单的脚本编写 但是也可以用于复杂的科学计算 求和是我们在编程中经常需要处理的基本操作之一 Python具有简单易学的语法和广泛的开源库 使其成为处理数据的强大工具 在本文
  • 2022CISCNmisc

    ez usb 题目已经告诉是usb流量 一共有三个地址2 8 2 10 2 4但2 4没用 我们分别导出2 8和2 10 从网上搜usb脚本将他们两个分别解出来 将那一打穿放到010发现是个rar文件 但是损坏了打不开 可以用winrar修
  • bp神经网络的训练方法,一文搞定bp神经网络

    BP人工神经网络方法 一 方法原理人工神经网络是由大量的类似人脑神经元的简单处理单元广泛地相互连接而成的复杂的网络系统 理论和实践表明 在信息处理方面 神经网络方法比传统模式识别方法更具有优势 人工神经元是神经网络的基本处理单元 其接收的信
  • -day17 面向对象基础

    第三模块 面向对象 网络 并发编程 此模块包含如下三大部分知识 面向对象 Python中支持两种编程方式来写代码 分别是 函数式编程 面向对象式编程 函数式 定义函数 在函数中实现功能 def func print 一个功能 执行函数 fu
  • mysql高可用分库分表ShardingSphere之Sharding-proxy

    文章目录 一 ShardingSphere 1 1 官网地址说明 1 2 为什么分库分表 二 官网整合说明 1 1 下载sharding proxy 1 2 sharding proxy集成注册中心 1 3 查看配置手册 1 3 1 官网数