分布式mysql proxy_mysqlda: 基于核心业务对象切分的Proxy模式的分布式MySQL数据库中间件...

mysqlda - MySQL数据库中间件

1. 概述

1.1. 数据分布式切分方式

分布式架构中最难解决的是数据分布式问题,大部分数据库中间件都以分库分表作为切分方式,好处是通用,但也存在以下问题:

扩容过程需要以切片为单位在库间移动数据。扩容规模受到切片数量限制,如果业务发展增长规模大大超出初期预估会导致切片数量不够用,陷入数据硬迁移的困境。

同一业务对象的数据分散在不同库中,无法做聚合、连接等复杂处理。

跨库意味着分布式事务,虽然现在有两阶段提交等解决方案,但理论上并不总是那么可靠,尤其是在金融行业苛求数据强一致性时。

以核心业务对象切分方式则以产品线入口业务对象作为切分目标(比如互联网业务系统中的客户对象),开户交易途径数据库中间件,以手机号或其它入口字段作为核心字段做附带权重的客群切分,归属到数据库集群中的某个库中,并保存分配结果,以后该客户的所有交易都会被发往其归属库处理。当需要库存储扩容时,只需简单的增加MySQL归属库到数据库集群中,在数据库中间件系统中增加新归属库配置信息,并调大新库被分配权重,新客户分配归属到新库的概率变大,当新库存储增长到一定程度时调平分配权重,新客户分配归属到所有库的概率均等,直到下一次扩容。

以核心业务对象切分方式的好处是:

无需预估切片数量,其扩容过程无需移动任何切片或数据。

由于同一业务对象的数据集中在其归属库中,所以可以进行任意聚合、连接等复杂处理。

每个库都是全业务库,同一业务对象的所有模块处理都在一个库中完成,不存在跨库分布式事务,数据强一致性丢还给数据库单库来保证。

但也存在以下硬伤:

产品线设计初期慎重挑选核心业务对象作为切分依据,后期很难变更。

有些业务系统存在多个核心业务对象,不适合使用这种切分方式,如银行线上线下整合核心。

以分库分表切分和以核心业务对象切分是两种主流的数据分布式设计范式,各有优缺点,应在不同场景挑选合适的方式。

1.2. mysqlda

mysqlda是一款基于核心业务对象切分的Proxy模式的分布式MySQL数据库中间件。

mysqlda优势:

以核心业务对象切分方式的所有好处。

支持以核心业务对象定位MySQL归属库(如开户用身份证号或手机号或邮箱),也支持核心业务对象的关联对象(如开户后的用户ID、用户名、账号)定位MySQL归属库。

归属库加权一致性哈希算法的分配权重自动调整,扩容后新库与老库的分配权重也自动调整,无需人工介入,使得所有归属库的数据量尽量自动均衡增长。

已包含数据库网关高可用机制,当一个归属库当前MySQL主服务器不可用时自动切换到备服务器,支持多个备服务器。

与MySQL服务器之间的连接池机制实现了连接复用和闲置清理,提高连接和切换性能。

通过在线重载配置文件,扩容新增MySQL归属库、调整MySQL服务器优先列表等完全无感。

2. 架构与原理

2.1. 体系架构

766c20a7fe55f5004a18d2d12581fc23.png

mysqlda数据库中间件完全遵循MySQL通讯协议桥接应用服务器集群和MySQL数据库集群。

mysqlda内部进程结构为“父-单子进程”。

2.2. 工作原理

全量数据以核心业务对象切分到多个归属库中,每个归属库包含全业务表。一个归属库由一个MySQL服务器列表(需部署为向下游同步数据)组成,当当前MySQL服务器不可用时自动切换到下一个。

MySQL数据库集群预创建相同的连接用户名、密码,相同的数据库名和应用表结构,mysqlda预创建相同的连接用户名、密码。

启动mysqlda,从配置文件(etc/mysqlda.conf)中装载连接用户名、密码,从保存文件(etc/mysqlda.save、etc/mysqlda.关联对象类.save)中装载已存在的核心业务对象、关联对象 与 MySQL数据库集群库 归属库关系信息。

应用服务器调用标准MySQL连接函数/方法连接mysqlda,mysqlda会遵循MySQL通讯协议处理MySQL用户登录和密码校验。

登录成功后,所有DSL、DML操作前,应用服务器发送mysqlda扩展SQL选择核心业务对象("select library (核心业务对象)")或关联对象类、关联对象("select library_by_correl_object (关联对象类) (关联对象)")以连接MySQL归属库,mysqlda会查询其已分配的MySQL库核心业务对象或关联对象类、关联对象(如果没有分配过则根据加权一致性哈希算法分配一个归属库并持久化到保存文件中),从该MySQL归属库对应数据库服务器有序列表中选择第一个有效MySQL服务器及其连接池中选取空闲连接(如没有缓存连接则新建一条连接),然后桥接对外和对内连接结对,开始处理后续所有DSL、DML操作。

后续操作中可以也发送mysqlda扩展SQL再选择核心业务对象或关联对象类、关联对象以调整MySQL归属库服务器连接。

MySQL归属库对应一个数据库服务器列表,如由MySQL数据库1A(MASTER)、1B(SLAVE)、1C(SLAVE)、1D(SLAVE)组成,1A同步复制数据给1B、1C和1D,如果1A出现故障不能被mysqlda连接,mysqlda会依次尝试连接1B、1C和1D,实现系统可用性。

应用服务器发送mysqlda扩展SQL绑定关联对象类和关联对象和核心业务对象("set correl_object 关联对象类 关联对象 核心业务对象"),mysqlda会保存该关系并持久化到保存文件中,供以后直接用关联对象类、关联对象定位MySQL归属库。

2.3. 简易案例

部署了三个MySQL归属库,每个库有主备两台MySQL服务器组成。

A用户用手机号(核心业务对象)开户,应用服务器发送手机号13812345678给mysqlda请求定位归属库("select library 13812341234"),mysqlda通过加权一致性哈希算法计算出该手机号(分配客户)归属库N并持久化到保存文件中,从归属库N连接池中取出一个连接,把该连接与应用服务器连接桥接,交换后面的所有SQL和处理结果。

开户业务逻辑中创建了账户331234567890,,应用服务器发送mysqlda扩展SQL给mysqla("set correl_object account_no 331234567890 13812345678"),mysqlda绑定两者关系并持久化到保存文件中。

A用户后续处理请求,可以送手机号("select library 13812341234")或账号("select library_by_correl_object account_no 331234567890")给mysqlda定位、连接用户归属库,该用户的所有业务数据和业务处理都在该归属库中完成。

2.4. 内部数据实体和关系

3412afa0d81d17746c017e3328f621d7.png

一个MySQL归属库(forward_instance)对应一个MySQL数据库服务器有序列表(forward_servers list)。

一个MySQL数据库服务器有序列表(forward_servers list)下辖一个空闲连接池(unused_forward_session list)和一个工作连接池(forward_session list)。

一个核心业务对象可以绑定一个或多个关联对象类(forward_correl_object_class)、关联对象(forward_correl_object)。

一个核心业务对象或一个关联对象类、关联对象 与 MySQL归属库 建立一个归属关系(forward_library)。

accepted_session是应用服务器与mysqlda之间的通讯会话,forward_session是mysqlda与MySQL数据库服务器之间的通讯会话,一旦一条连接上的MySQL归属库被选定或切换,这两个会话会被桥接起来。

3. 安装部署

mysqlda只依赖于mysql或mariadb,必须先安装好开发包*-devel-*。

3.1. 解开mysqlda源码包 或 直接从源码托管地址克隆最新版

$git clone http://git.oschina.net/calvinwilliams/mysqlda

Cloning into 'mysqlda'...

remote: Counting objects: 355, done.

remote: Compressing objects: 100% (345/345), done.

remote: Total 355 (delta 221), reused 0 (delta 0)

Receiving objects: 100% (355/355), 586.04 KiB | 0 bytes/s, done.

Resolving deltas: 100% (221/221), done.

3.2. 进入src目录,清理中间文件

$cdmysqlda

$make -f makefile.Linux clean

make[1]: Entering directory `/home/calvin/src/mysqlda/src'

make[2]: Entering directory `/home/calvin/src/mysqlda/src/mysqlda'

rm -f lk_list.o

rm -f rbtree.o

rm -f LOGC.o

rm -f fasterjson.o

rm -f util.o

rm -f rbtree_ins.o

rm -f IDL_mysqlda_conf.dsc.o

rm -f main.o

rm -f config.o

rm -f monitor.o

rm -f worker.o

rm -f comm.o

rm -f app.o

rm -f mysqlda

make[2]: Leaving directory `/home/calvin/src/mysqlda/src/mysqlda'

make[1]: Leaving directory `/home/calvin/src/mysqlda/src'

make[1]: Entering directory `/home/calvin/src/mysqlda/shbin'

make[1]: Leaving directory `/home/calvin/src/mysqlda/shbin'

make[1]: Entering directory `/home/calvin/src/mysqlda/test'

rm -f mysqlda_test_connect.o

rm -f mysqlda_test_select_library.o

rm -f mysqlda_test_set_correl_object.o

rm -f mysqlda_test_select_library_by_correl_object.o

rm -f mysqlda_test_insert.o

rm -f mysqlda_test_update.o

rm -f mysqlda_test_delete.o

rm -f mysqlda_test_connect

rm -f mysqlda_test_select_library

rm -f mysqlda_test_set_correl_object

rm -f mysqlda_test_select_library_by_correl_object

rm -f mysqlda_test_insert

rm -f mysqlda_test_update

rm -f mysqlda_test_delete

make[1]: Leaving directory `/home/calvin/src/mysqlda/test'

3.3. 修改安装目标目录

可执行文件mysqlda默认编译链接出来后安装到$HOME/bin,如需调整目标目录可编辑src/mysqlda/makeinstall

_BINBASE = $(HOME)/bin

管理脚本mysqlda.sh默认编译链接出来后安装到$HOME/shbin,如需调整目标目录可编辑shbin/makeinstall

NOCLEAN_OBJINST = $(HOME)/shbin

没特殊需求可以不修改

3.4. 编译、安装

$make -f makefile.Linux install

make[1]: Entering directory `/home/calvin/src/mysqlda/src'

make[2]: Entering directory `/home/calvin/src/mysqlda/src/mysqlda'

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c lk_list.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c rbtree.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c LOGC.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c fasterjson.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c util.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c rbtree_ins.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c IDL_mysqlda_conf.dsc.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c main.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c config.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c monitor.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c worker.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c comm.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include/mysqlda_api -std=gnu99 -I/usr/include/mysql -c app.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda lk_list.o rbtree.o LOGC.o fasterjson.o util.o rbtree_ins.o IDL_mysqlda_conf.dsc.o main.o config.o monitor.o worker.o comm.o app.o -L. -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient -lcrypto

cp -rf mysqlda /home/calvin/bin/

make[2]: Leaving directory `/home/calvin/src/mysqlda/src/mysqlda'

make[1]: Leaving directory `/home/calvin/src/mysqlda/src'

make[1]: Entering directory `/home/calvin/src/mysqlda/shbin'

cp -rf mysqlda.sh /home/calvin/shbin/

make[1]: Leaving directory `/home/calvin/src/mysqlda/shbin'

make[1]: Entering directory `/home/calvin/src/mysqlda/test'

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_connect.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_connect mysqlda_test_connect.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_select_library.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_select_library mysqlda_test_select_library.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_set_correl_object.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_set_correl_object mysqlda_test_set_correl_object.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_select_library_by_correl_object.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_select_library_by_correl_object mysqlda_test_select_library_by_correl_object.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_insert.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_insert mysqlda_test_insert.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_update.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_update mysqlda_test_update.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/include -std=gnu99 -I/usr/include/mysql -c mysqlda_test_delete.c

gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o mysqlda_test_delete mysqlda_test_delete.o -L. -L/home/calvin/lib -L/home/calvin/lib -L/usr/lib64/mysql -lmysqlclient

make[1]: Leaving directory `/home/calvin/src/mysqlda/test'

3.5. 查询版本号,也确认可执行文件OK

$mysqlda -v

mysqlda v0.0.6.0

4. 配置使用

4.1. 自动生成缺省配置文件

$mysqlda -a init

$cat ~/etc/mysqlda.conf

{

"server" :

{

"listen_ip" : "127.0.0.1" ,

"listen_port" : 13306

} ,

"auth" :

{

"user" : "calvin" ,

"pass" : "calvin" ,

"db" : "calvindb"

} ,

"session_pool" :

{

"unused_forward_session_timeout" : 60

} ,

"forwards" :

[

{

"instance" : "mysqlda1" ,

"forward" :

[

{

"ip" : "127.0.0.1" ,

"port" : 3306

}

]

}

]

}

各配置项说明如下:

server.listen_ip : mysqlda面向应用服务器的侦听IP

server.listen_port : mysqlda面向应用服务器的侦听PORT

auth.user : mysqlda面向应用服务器的登录认证用户名,也是mysqlda面向MySQL数据库服务器列表集群的登录认证用户名

auth.pass : mysqlda面向应用服务器的登录认证用户密码,也是mysqlda面向MySQL数据库服务器列表集群的登录认证用户密码

auth.db : mysqlda面向应用服务器的登录数据库,也是mysqlda面向MySQL数据库服务器列表集群的登录数据库

session_pool.unused_forward_session_timeout : mysqlda面向MySQL数据库服务器列表集群的空闲连接池超时清理时间

forwards[].instance : MySQL归属库ID

forwards[].forward[].ip : MySQL归属库服务器IP

forwards[].forward[].port : MySQL归属库服务器PORT

4.2. 启动mysqlda

不带命令行参数直接执行mysqlda会得到完整参数列表,根据实际环境修改完配置文件后启动

$mysqlda

USAGE : mysqlda -f (config_filename) --no-daemon -a [ init | start ]

[ --loglevel-debug | --loglevel-info | --loglevel-notice

| --loglevel-warn | --loglevel-error | --loglevel-fatal ]

-v

$mysqlda -a start

注意:默认日志等级为NOTICE,如果想以调试等级启动,加上命令行参数--loglevel-debug。

也可以使用管理脚本启动

$mysqlda.sh

USAGE : mysqlda.sh [ status | start | stop | kill | restart | reload ] *

$mysqlda.sh start

注意:mysqlda.sh第二个参数开始的参数列表会传递给mysqlda -a start后面。

查询启动日志(以我的环境参数配置)

$view ~/log/mysqlda.log

2017-09-03 14:17:17.306390 | NOTICE | 18582:monitor.c:75 | [18582]fork[18583] ok

2017-09-03 14:17:17.306460 | NOTICE | 18582:monitor.c:69 | [18582]fork[18583] ok

2017-09-03 14:17:17.307423 | NOTICE | 18583:config.c:259 | Load forward_library /home/calvin/etc/mysqlda.save ok , count[2000]

2017-09-03 14:17:17.307452 | NOTICE | 18583:config.c:358 | Load all forward_correl_object_class ok , count[0]

2017-09-03 14:17:17.307456 | NOTICE | 18583:config.c:369 | instance[0x225a180][mysql_data_1] serial_range_begin[0] power[989]

2017-09-03 14:17:17.307459 | NOTICE | 18583:config.c:373 | ip[192.168.6.22] port[3306]

2017-09-03 14:17:17.307462 | NOTICE | 18583:config.c:369 | instance[0x225a260][mysql_data_2] serial_range_begin[989] power[1013]

2017-09-03 14:17:17.307464 | NOTICE | 18583:config.c:373 | ip[192.168.6.23] port[3306]

2017-09-03 14:17:17.307467 | NOTICE | 18583:config.c:377 | total_power[2002]

2017-09-03 14:17:17.307475 | NOTICE | 18583:worker.c:204 | epoll_create ok , #1#

2017-09-03 14:17:17.307479 | NOTICE | 18583:worker.c:219 | epoll_ctl #1# add alive_pipe_session #0# ok

2017-09-03 14:17:17.307488 | NOTICE | 18583:worker.c:231 | socket ok , #2#

2017-09-03 14:17:17.307499 | NOTICE | 18583:worker.c:248 | bind[192.168.6.21:13306] #2# ok

2017-09-03 14:17:17.307506 | NOTICE | 18583:worker.c:260 | listen[192.168.6.21:13306] #2# ok

2017-09-03 14:17:17.307509 | NOTICE | 18583:worker.c:275 | epoll_ctl #1# add listen_session #2# ok

2017-09-03 14:17:17.308110 | NOTICE | 18583:worker.c:293 | [mysql_data_1]mysql_real_connect[192.168.6.22][3306][calvin][calvin][calvindb] connecting ...

2017-09-03 14:17:17.309869 | NOTICE | 18583:worker.c:302 | [mysql_data_1]mysql_real_connect[192.168.6.22][3306][calvin][calvin][calvindb] connecting ok

2017-09-03 14:17:17.310148 | NOTICE | 18583:worker.c:313 | [mysql_data_1]mysql_close[192.168.6.22][3306] ok

2017-09-03 14:17:17.310219 | NOTICE | 18583:worker.c:293 | [mysql_data_2]mysql_real_connect[192.168.6.23][3306][calvin][calvin][calvindb] connecting ...

2017-09-03 14:17:17.311103 | NOTICE | 18583:worker.c:302 | [mysql_data_2]mysql_real_connect[192.168.6.23][3306][calvin][calvin][calvindb] connecting ok

2017-09-03 14:17:17.311119 | NOTICE | 18583:worker.c:313 | [mysql_data_2]mysql_close[192.168.6.23][3306] ok

2017-09-03 14:17:18.313143 | NOTICE | 18583:worker.c:345 | epoll_wait #1# return[0]events

2017-09-03 14:17:19.315163 | NOTICE | 18583:worker.c:345 | epoll_wait #1# return[0]events

2017-09-03 14:17:20.316408 | NOTICE | 18583:worker.c:345 | epoll_wait #1# return[0]events

则表示启动成功

如果mysqlda连接MySQL数据库集群有问题,启动初始化阶段会侦测出来

2017-09-03 14:17:17.306390 | NOTICE | 18582:monitor.c:75 | [18582]fork[18583] ok

2017-09-03 14:17:17.306460 | NOTICE | 18582:monitor.c:69 | [18582]fork[18583] ok

2017-09-03 14:17:17.307423 | NOTICE | 18583:config.c:259 | Load forward_library /home/calvin/etc/mysqlda.save ok , count[2000]

2017-09-03 14:17:17.307452 | NOTICE | 18583:config.c:358 | Load all forward_correl_object_class ok , count[0]

2017-09-03 14:17:17.307456 | NOTICE | 18583:config.c:369 | instance[0x225a180][mysql_data_1] serial_range_begin[0] power[989]

2017-09-03 14:17:17.307459 | NOTICE | 18583:config.c:373 | ip[192.168.6.22] port[3306]

2017-09-03 14:17:17.307462 | NOTICE | 18583:config.c:369 | instance[0x225a260][mysql_data_2] serial_range_begin[989] power[1013]

2017-09-03 14:17:17.307464 | NOTICE | 18583:config.c:373 | ip[192.168.6.23] port[3306]

2017-09-03 14:17:17.307467 | NOTICE | 18583:config.c:377 | total_power[2002]

2017-09-03 14:17:17.307475 | NOTICE | 18583:worker.c:204 | epoll_create ok , #1#

2017-09-03 14:17:17.307479 | NOTICE | 18583:worker.c:219 | epoll_ctl #1# add alive_pipe_session #0# ok

2017-09-03 14:17:17.307488 | NOTICE | 18583:worker.c:231 | socket ok , #2#

2017-09-03 14:17:17.307499 | NOTICE | 18583:worker.c:248 | bind[192.168.6.21:13306] #2# ok

2017-09-03 14:17:17.307506 | NOTICE | 18583:worker.c:260 | listen[192.168.6.21:13306] #2# ok

2017-09-03 14:17:17.307509 | NOTICE | 18583:worker.c:275 | epoll_ctl #1# add listen_session #2# ok

2017-09-03 14:17:17.308110 | NOTICE | 18583:worker.c:293 | [mysql_data_1]mysql_real_connect[192.168.6.22][3306][calvin][calvin][calvindb] connecting ...

2017-08-28 14:17:17.308110 | ERROR | 53070:worker.c:130 | [mysql_data_1]mysql_real_connect[192.168.6.22][13306][calvin][calvin][calvindb] failed , mysql_errno[2003][Can't connect to MySQL server on '192.168.6.22' (113)]

2017-08-28 14:17:17.308110 | INFO | 53070:worker.c:482 | worker exit ...

4.3. 停止mysqlda

直接ps出来发送TERM信号即可,如果停不掉就发送KILL信号

$ps -ef | grepmysqlda

calvin 53069 1 0 00:12 pts/1 00:00:00 mysqlda -a start

calvin 53097 53072 0 00:12 pts/2 00:00:00 view mysqlda.log

calvin 53111 52899 0 00:12 pts/1 00:00:00 grep --color=auto mysqlda

$kill53069

也可以使用管理脚本停止

$mysqlda.sh stop

4.4. 扩容MySQL数据库集群

4.4.1. 增加MySQL归属库

在配置文件mysqlda.conf中新增一个forwards[],至少一个MySQL服务器forward,如以下新增了MySQL归属库mysql_data_3:

"forwards" :

[

{

"instance" : "mysql_data_1" ,

"forward" :

[

{ "ip" : "192.168.6.11" , "port" : 13306 } ,

{ "ip" : "192.168.6.12" , "port" : 13306 } ,

{ "ip" : "192.168.6.13" , "port" : 13306 }

]

} ,

{

"instance" : "mysql_data_2" ,

"forward" :

[

{ "ip" : "192.168.6.21" , "port" : 13306 } ,

{ "ip" : "192.168.6.22" , "port" : 13306 } ,

{ "ip" : "192.168.6.23" , "port" : 13306 }

]

} ,

{

"instance" : "mysql_data_3" ,

"forward" :

[

{ "ip" : "192.168.6.31" , "port" : 13306 } ,

{ "ip" : "192.168.6.32" , "port" : 13306 } ,

{ "ip" : "192.168.6.33" , "port" : 13306 }

]

}

]

发送USR1信号到mysqlda父进程。

注意:产生存量保存信息后一般不会修改或删除MySQL归属库。

4.4.2. 调整MySQL归属库服务器列表

在配置文件mysqlda.conf中新增一个forwards[],至少一个MySQL服务器forward,如以下每个MySQL归属库都增加了一台MySQL服务器:

"forwards" :

[

{

"instance" : "mysql_data_1" ,

"forward" :

[

{ "ip" : "192.168.6.11" , "port" : 13306 } ,

{ "ip" : "192.168.6.12" , "port" : 13306 } ,

{ "ip" : "192.168.6.13" , "port" : 13306 } ,

{ "ip" : "192.168.6.14" , "port" : 13306 }

]

} ,

{

"instance" : "mysql_data_2" ,

"forward" :

[

{ "ip" : "192.168.6.21" , "port" : 13306 } ,

{ "ip" : "192.168.6.22" , "port" : 13306 } ,

{ "ip" : "192.168.6.23" , "port" : 13306 } ,

{ "ip" : "192.168.6.24" , "port" : 13306 }

]

}

]

发送USR1信号到mysqlda父进程以重载配置,也可以使用管理脚本。

$mysqlda.sh reload

注意:理论上支持在一个MySQL归属库中修改和删除一台MySQL服务器,但会立即断开这台MySQL服务器的所有连接。

5. 保存文件输出格式

5.1. 核心业务对象-MySQL归属库 保存文件格式

每个核心业务对象建立归属关系后都会输出其关系到保存文件

文件名规则如下:

$HOME/etc/mysqlda.save

文件格式如下:

建立的日期 建立的时间 核心业务对象 MySQL归属库

示例如下:

2017-08-24 22:17:11 1 mysql_data_2

2017-08-26 16:34:31 2 mysql_data_1

2017-08-26 16:34:31 3 mysql_data_1

2017-08-26 16:34:31 4 mysql_data_1

2017-08-26 16:34:31 5 mysql_data_2

2017-08-26 16:34:31 6 mysql_data_1

2017-08-26 16:34:31 7 mysql_data_1

2017-08-26 16:34:31 8 mysql_data_1

2017-08-26 16:34:31 9 mysql_data_1

2017-08-26 16:34:31 10 mysql_data_1

5.2. 关联对象类、关联对象-核心业务对象 保存文件格式

每个关联对象类、关联对象和核心业务对象建立关系后都会输出其关系到保存文件

文件名规则如下:

$HOME/etc/mysqlda.(关联对象类).save

文件格式如下:

建立的日期 建立的时间 关联对象 核心业务对象

示例如下:

2017-08-26 18:11:42 330001 2

2017-08-26 18:12:41 330002 3

6. 开发示例

6.1. 说明

新增了三条mysqlda扩展SQL用于定位MySQL归属库、绑定关联对象等。

6.1.1. 用核心业务对象定位MySQL归属库

开发流程中,只需在连接函数/方法后,SQL执行前,插入mysqlda扩展SQL通过核心业务对象定位归属库:

select library (核心业务对象)

mysqlda会根据核心业务对象查询与MySQL归属库集合中一个归属库的映射关系,没有则用加权一致性哈希算法新建并持久化到保存文件中。

6.1.2. 用关联对象类、关联对象绑定到核心业务对象

关联对象类、关联对象 与 核心业务对象 绑定关系由mysqlda扩展SQL设置,并持久化到保存文件中:

set correl_object (关联对象类) (关联对象) (核心业务对象)

6.1.3. 用关联对象类、关联对象定位MySQL归属库

也可以通过mysqlda扩展SQL用关联对象类、关联对象定位归属库:

select library_by_correl_object (关联对象类) (关联对象)

mysqlda会根据关联对象类、关联对象查询绑定的核心业务对象,再查询其归属库。

6.2. C语言示例

项目主目录的test目录里是测试程序源码。

6.2.1. 用核心业务对象定位MySQL归属库

该测试程序用于给定一个序号区间,批量的建立和定位MySQL归属库。

注意:也可以直接用客户端mysql连接服务器执行SQL"select library (核心业务对象);"得到等价效果。

测试程序示例如下:

$ cat test/mysqlda_test_select_library.c

#include

#include

#include

#include

#include "my_global.h"

#include "mysql.h"

/*

./mysqlda_test_connect "192.168.6.21" 13306 calvin calvin calvindb

*/

static void usage()

{

printf( "USAGE : mysqlda_test_connect (ip) (port) (user) (pass) (database)\n" );

return;

}

int main( int argc , char *argv[] )

{

MYSQL*conn = NULL ;

char*ip = NULL ;

unsigned intport ;

char*user = NULL ;

char*pass = NULL ;

char*database = NULL ;

if( argc != 1 + 5 )

{

usage();

exit(7);

}

printf( "mysql_get_client_info[%s]\n" , mysql_get_client_info() );

conn = mysql_init(NULL) ;

if( conn == NULL )

{

printf( "mysql_init failed\n" );

return 1;

}

ip = argv[1] ;

port = (unsigned int)atoi(argv[2]) ;

user = argv[3] ;

pass = argv[4] ;

database = argv[5] ;

if( mysql_real_connect( conn , ip , user , pass , database , port , NULL , 0 ) == NULL )

{

printf( "mysql_real_connect failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

return 1;

}

else

{

printf( "mysql_real_connect ok\n" );

}

mysql_close( conn );

printf( "mysql_close\n" );

return 0;

}

6.2.2. 用关联对象类、关联对象绑定到核心业务对象

该测试程序用于给定关联对象类、关联对象、核心业务对象,建立其关系

注意:也可以直接用客户端mysql连接服务器执行SQL"set correl_object 关联对象类 关联对象 核心业务对象;"得到等价效果。

测试程序示例如下:

$ cat test/mysqlda_test_set_correl_object.c

#include

#include

#include

#include

#include "my_global.h"

#include "mysql.h"

/*

./mysqlda_test_set_correl_object "192.168.6.21" 13306 calvin calvin calvindb card_no 330001 1

*/

static void usage()

{

printf( "USAGE : mysqlda_test_set_correl_object (ip) (port) (user) (pass) (database) (correl_object_class) (correl_object) (library)\n" );

return;

}

int main( int argc , char *argv[] )

{

MYSQL*conn = NULL ;

char*ip = NULL ;

unsigned intport ;

char*user = NULL ;

char*pass = NULL ;

char*database = NULL ;

char*correl_object_class = NULL ;

char*correl_object = NULL ;

char*library = NULL ;

charsql[ 4096 + 1 ] ;

intnret = 0 ;

if( argc != 1 + 8 )

{

usage();

exit(7);

}

printf( "mysql_get_client_info[%s]\n" , mysql_get_client_info() );

conn = mysql_init(NULL) ;

if( conn == NULL )

{

printf( "mysql_init failed\n" );

return 1;

}

ip = argv[1] ;

port = (unsigned int)atoi(argv[2]) ;

user = argv[3] ;

pass = argv[4] ;

database = argv[5] ;

if( mysql_real_connect( conn , ip , user , pass , database , port , NULL , 0 ) == NULL )

{

printf( "mysql_real_connect failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

return 1;

}

else

{

printf( "mysql_real_connect ok\n" );

}

correl_object_class = argv[6] ;

correl_object = argv[7] ;

library = argv[8] ;

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "set correl_object %s %s %s" , correl_object_class , correl_object , library );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query ok\n" );

}

mysql_close( conn );

printf( "mysql_close\n" );

return 0;

}

6.2.3. 用关联对象类、关联对象定位MySQL归属库

该测试程序用于给定一个序号区间,批量的建立和定位MySQL归属库

注意:也可以直接用客户端mysql连接服务器执行SQL"select library_by_correl_object 关联对象类 关联对象;"得到等价效果。

测试程序示例如下:

$ cat test/mysqlda_test_select_library_by_correl_object.c

#include

#include

#include

#include

#include "my_global.h"

#include "mysql.h"

/*

./mysqlda_test_select_library_by_correl_object "192.168.6.21" 13306 calvin calvin calvindb card_no 330001

*/

static void usage()

{

printf( "USAGE : mysqlda_test_select_library_by_correl_object (ip) (port) (user) (pass) (database) (correl_object_class) (correl_object)\n" );

return;

}

int main( int argc , char *argv[] )

{

MYSQL*conn = NULL ;

char*ip = NULL ;

unsigned intport ;

char*user = NULL ;

char*pass = NULL ;

char*database = NULL ;

char*correl_object_class = NULL ;

char*correl_object = NULL ;

charsql[ 4096 + 1 ] ;

intnret = 0 ;

if( argc != 1 + 7 )

{

usage();

exit(7);

}

printf( "mysql_get_client_info[%s]\n" , mysql_get_client_info() );

conn = mysql_init(NULL) ;

if( conn == NULL )

{

printf( "mysql_init failed\n" );

return 1;

}

ip = argv[1] ;

port = (unsigned int)atoi(argv[2]) ;

user = argv[3] ;

pass = argv[4] ;

database = argv[5] ;

if( mysql_real_connect( conn , ip , user , pass , database , port , NULL , 0 ) == NULL )

{

printf( "mysql_real_connect failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

return 1;

}

else

{

printf( "mysql_real_connect ok\n" );

}

correl_object_class = argv[6] ;

correl_object = argv[7] ;

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "select library_by_correl_object %s %s" , correl_object_class , correl_object );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query ok\n" );

}

mysql_close( conn );

printf( "mysql_close\n" );

return 0;

}

6.2.4. 用核心业务对象定位MySQL归属库、然后批量执行INSERT语句

该测试程序用于给定一个序号区间,批量的建立、定位MySQL归属库、执行INSERT语句

测试程序示例如下:

$ cat test/mysqlda_test_insert.c

#include

#include

#include

#include

#include "my_global.h"

#include "mysql.h"

/*

./mysqlda_test_insert "192.168.6.21" 13306 calvin calvin calvindb 1 1000

*/

static void usage()

{

printf( "USAGE : mysqlda_test_insert (ip) (port) (user) (pass) (database) (begin_seqno) (end_seqno)\n" );

return;

}

int main( int argc , char *argv[] )

{

MYSQL*conn = NULL ;

char*ip = NULL ;

unsigned intport ;

char*user = NULL ;

char*pass = NULL ;

char*database = NULL ;

intbegin_seqno ;

intend_seqno ;

intseqno ;

charseqno_buffer[ 20 + 1 ] ;

charsql[ 4096 + 1 ] ;

intnret = 0 ;

if( argc != 1 + 7 )

{

usage();

exit(7);

}

printf( "mysql_get_client_info[%s]\n" , mysql_get_client_info() );

conn = mysql_init(NULL) ;

if( conn == NULL )

{

printf( "mysql_init failed\n" );

return 1;

}

ip = argv[1] ;

port = (unsigned int)atoi(argv[2]) ;

user = argv[3] ;

pass = argv[4] ;

database = argv[5] ;

if( mysql_real_connect( conn , ip , user , pass , database , port , NULL , 0 ) == NULL )

{

printf( "mysql_real_connect failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

return 1;

}

else

{

printf( "mysql_real_connect ok\n" );

}

memset( seqno_buffer , 0x00 , sizeof(seqno_buffer) );

begin_seqno = atoi(argv[6]) ;

end_seqno = atoi(argv[7]) ;

for( seqno = begin_seqno ; seqno <= end_seqno ; seqno++ )

{

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "select library %d" , seqno );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query[%s] failed , mysql_errno[%d][%s]\n" , sql , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query[%s] ok\n" , sql );

}

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "insert into test_table value( '%d' , '%d' )" , seqno , seqno );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query[%s] failed , mysql_errno[%d][%s]\n" , sql , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query[%s] ok\n" , sql );

}

}

mysql_close( conn );

printf( "mysql_close\n" );

return 0;

}

6.2.5. 用核心业务对象定位MySQL归属库、然后批量执行UPDATE语句

该测试程序用于给定一个序号区间,批量建立、定位MySQL归属库、执行UPDATE语句

测试程序示例如下:

$ cat test/mysqlda_test_update.c

#include

#include

#include

#include

#include "my_global.h"

#include "mysql.h"

/*

./mysqlda_test_update "192.168.6.21" 13306 calvin calvin calvindb 1 1000

*/

static void usage()

{

printf( "USAGE : mysqlda_test_update (ip) (port) (user) (pass) (database) (begin_seqno) (end_seqno)\n" );

return;

}

int main( int argc , char *argv[] )

{

MYSQL*conn = NULL ;

char*ip = NULL ;

unsigned intport ;

char*user = NULL ;

char*pass = NULL ;

char*database = NULL ;

intbegin_seqno ;

intend_seqno ;

intseqno ;

charseqno_buffer[ 20 + 1 ] ;

charsql[ 4096 + 1 ] ;

intnret = 0 ;

if( argc != 1 + 7 )

{

usage();

exit(7);

}

printf( "mysql_get_client_info[%s]\n" , mysql_get_client_info() );

conn = mysql_init(NULL) ;

if( conn == NULL )

{

printf( "mysql_init failed\n" );

return 1;

}

ip = argv[1] ;

port = (unsigned int)atoi(argv[2]) ;

user = argv[3] ;

pass = argv[4] ;

database = argv[5] ;

if( mysql_real_connect( conn , ip , user , pass , database , port , NULL , 0 ) == NULL )

{

printf( "mysql_real_connect failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

return 1;

}

else

{

printf( "mysql_real_connect ok\n" );

}

memset( seqno_buffer , 0x00 , sizeof(seqno_buffer) );

begin_seqno = atoi(argv[6]) ;

end_seqno = atoi(argv[7]) ;

for( seqno = begin_seqno ; seqno <= end_seqno ; seqno++ )

{

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "select library %d" , seqno );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query[%s] failed , mysql_errno[%d][%s]\n" , sql , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query[%s] ok\n" , sql );

}

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "update test_table set value='%d' where name='%d'" , seqno , seqno );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query[%s] failed , mysql_errno[%d][%s]\n" , sql , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query[%s] ok\n" , sql );

}

}

mysql_close( conn );

printf( "mysql_close\n" );

return 0;

}

6.2.6. 用核心业务对象定位MySQL归属库、然后批量执行DELETE语句

该测试程序用于给定一个序号区间,批量的建立、定位MySQL归属库、执行DELETE语句

测试程序示例如下:

$ cat test/mysqlda_test_delete.c

#include

#include

#include

#include

#include "my_global.h"

#include "mysql.h"

/*

./mysqlda_test_delete "192.168.6.21" 13306 calvin calvin calvindb 1 1000

*/

static void usage()

{

printf( "USAGE : mysqlda_test_delete (ip) (port) (user) (pass) (database) (begin_seqno) (end_seqno)\n" );

return;

}

int main( int argc , char *argv[] )

{

MYSQL*conn = NULL ;

char*ip = NULL ;

unsigned intport ;

char*user = NULL ;

char*pass = NULL ;

char*database = NULL ;

intbegin_seqno ;

intend_seqno ;

intseqno ;

charseqno_buffer[ 20 + 1 ] ;

charsql[ 4096 + 1 ] ;

intnret = 0 ;

if( argc != 1 + 7 )

{

usage();

exit(7);

}

printf( "mysql_get_client_info[%s]\n" , mysql_get_client_info() );

conn = mysql_init(NULL) ;

if( conn == NULL )

{

printf( "mysql_init failed\n" );

return 1;

}

ip = argv[1] ;

port = (unsigned int)atoi(argv[2]) ;

user = argv[3] ;

pass = argv[4] ;

database = argv[5] ;

if( mysql_real_connect( conn , ip , user , pass , database , port , NULL , 0 ) == NULL )

{

printf( "mysql_real_connect failed , mysql_errno[%d][%s]\n" , mysql_errno(conn) , mysql_error(conn) );

return 1;

}

else

{

printf( "mysql_real_connect ok\n" );

}

memset( seqno_buffer , 0x00 , sizeof(seqno_buffer) );

begin_seqno = atoi(argv[6]) ;

end_seqno = atoi(argv[7]) ;

for( seqno = begin_seqno ; seqno <= end_seqno ; seqno++ )

{

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "select library %d" , seqno );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query[%s] failed , mysql_errno[%d][%s]\n" , sql , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query[%s] ok\n" , sql );

}

memset( sql , 0x00 , sizeof(sql) );

snprintf( sql , sizeof(sql) , "delete from test_table where name='%d'" , seqno );

nret = mysql_query( conn , sql ) ;

if( nret )

{

printf( "mysql_query[%s] failed , mysql_errno[%d][%s]\n" , sql , mysql_errno(conn) , mysql_error(conn) );

mysql_close( conn );

return 1;

}

else

{

printf( "mysql_query[%s] ok\n" , sql );

}

}

mysql_close( conn );

printf( "mysql_close\n" );

return 0;

}

7. 其它注意事项

7.1. 用客户端mysql直连mysqlda

可以用客户端mysql直接连接mysqlda,如"mysql --host 192.168.6.21 --port 3306 -u calvin -p",但暂时不支持命令行中直接指定数据库。

不用指定数据库,mysqlda已经用配置文件中的参数use数据库了。

登录成功后的第一条命令必须是选择后端MySQL归属库,后续才能执行DDL、DSL、DML等SQL。

8. 最后

8.1. 后续研发

寻求JAVA环境测试

现在只支持mysqlda单服务器,正在设计实现mysqlda服务器集群机制。

内存使用优化

更少的性能衰减

更多功能...

8.2. 源码托管

8.3. 作者邮箱

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/523555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业级实战01_ActiveMQ 下载、安装、运行、实战需求

ActiveMQ 下载、安装、运行、实战需求 文章目录一、ActiveMQ简介1. 什么是ActiveMQ&#xff1f;2. ActiveMQ能干什么&#xff1f;3. ActiveMQ特点4. MOM基本功能5. MOM主要特点6. MOM的应用场景_前7. MOM的应用场景_后二、ActiveMQ下载/安装2.1 ActiveMQ下载2.2 ActiveMQ安装环…

刚出炉!AI指数报告:AI人才需求暴涨35倍,薪酬问鼎No.1

2017年~2018年&#xff0c;是人工智能大火的时候。你会发现&#xff0c;跟朋友聊天不谈人工智能&#xff0c;聊天的bigger都上不去。国家支持的朝阳行业&#xff0c;顶级高薪吸引&#xff0c;让甚至许多不是计算机出身的小白&#xff0c;都按捺不住&#xff0c;投身“学海”。而…

企业实战01_Linux下安装ActiveMQ并设置开机启动

文章目录一、MQ常用命令二、防火墙常用命令三、MQ安装3.1. 在root权限下操作&#xff0c;赋予目录权限3.2. 给运行程序赋予可执行权限3.3. 配置环境变量四、MQ添加开机启动4.1. 添加开机启动至初始化目录4.2. 添加MQ内容如下4.3. 将activemq添加至配置文件4.4. 查看服务是否添加…

SDN精华问答 | 使用SDN的一个例子

SDN火热了好一阵子&#xff0c;无论运营商、政府企业、投资机构&#xff0c;一段时间&#xff0c;不知道SDN、不能甩几个SDN相关的名词术语&#xff0c;似乎都落后于时代了。今天&#xff0c;就来看看关于SDN的精华问答吧。1Q&#xff1a;为什么会出现SDN呢&#xff1f; A&…

企业级实战02_SpringMVC整合ActiveMQ 实战需求

SpringMVC整合ActiveMQ 文章目录一、Spring整合ActiveMQ实战1.1. 创建一个父工程&#xff1a;1.2. 引入依赖1.3. 创建一个子项目生产者1.4. 创建一个spring配置文件4. 创建一个点对点的生产者监听5. 创建一个topic的生产者监听四、Spring整合ActiveMQ实战1. 创建一个消费者工程…

苹果WWDC前瞻之iOS 13更新最受关注;微软发布基于区块链的去中心化身份识别系统;小米成立了新集团质量办公室……...

关注并标星星CSDN云计算极客头条&#xff1a;速递、最新、绝对有料。这里有企业新动、这里有业界要闻&#xff0c;打起十二分精神&#xff0c;紧跟fashion你可以的&#xff01;每周三次&#xff0c;打卡即read更快、更全了解泛云圈精彩newsgo go go SpaceX猎鹰9号火箭发射&…

企业级实战03_真实项目实战SpringMVC整合ActiveMQ

创建2个工程&#xff0c;生产者和消费者 测试点对点和广播发送常见类型的消息例如&#xff1a;文本(String)、对象(Object) 文本转Long String text “123”; Long.parseLong(text) 数组转集合 Arrays.toArray(list) 引入依赖 <?xml version"1.0" enco…

新一代私有云来了!看透基于开源生态的产品化

戳蓝字“CSDN云计算”关注我们哦&#xff01;文 | 易捷行云&#xff08;EasyStack&#xff09;创始人 陈喜伦来源 | 开源云中文社区进入云计算大时代&#xff0c;中大客户和产业互联网化是云计算的主战场&#xff0c;获取企业级客户是主旋律。对企业级客户来说以新一代私有云为…

mysql 用户管理表_mysql用户管理

msyql用户定义&#xff1a;使用某个用户 从哪个(些)地址访问我的数据库主机范围单独IP&#xff1a;10.0.0.200一个网段:10.0.0.% --->10.0.0.1-->10.0.0.254一个地址范围&#xff1a;10.0.0.5% ---->50-59用户的功能&#xff1a;1、用来登录mysql数据库2、用来管理数据…

8月有望推出5G套餐,资费或低于4G价格;为专利技术,华为5000万美元收购技术公司;AMD和三星宣布合作……...

关注并标星星CSDN云计算极客头条&#xff1a;速递、最新、绝对有料。这里有企业新动、这里有业界要闻&#xff0c;打起十二分精神&#xff0c;紧跟fashion你可以的&#xff01;每周三次&#xff0c;打卡即read更快、更全了解泛云圈精彩newsgo go go 宝宝树孕育APP新增即时交互功…

从数组随机抽取5个不重复_Power Query 如何保证随机抽取元素不重复

继续昨天的话题&#xff0c;昨天我们实现完全的随抽取列表元素&#xff0c;有一个问题就是可能几次会抽取同一个位置的元素&#xff1a;1-50中随机抽取5个数值&#xff0c;点击刷新&#xff0c;就会出现不同的结果&#xff0c;如上图可能会出现两个相同的数值&#xff0c;如何确…

vba上传指定文件ftp服务器

文章目录一、需求分析&#xff1a;二、操作流程&#xff1a;2.1 【开发工具】-【宏】2.2 【宏】-【编辑】2.3 【把脚本复制进去】2.4 脚本如下2.5 修改位置2.5.1 修改sheet名称和表格一致2.5.2 修改Cells(2,3)2.5.3 修改4 to 1002.5.4 修改Cells(i,3)2.5.5 修改发ftp信息2.5.6 …

云存储精华问答 | 云存储是如何工作的?

云存储是一种网上在线存储&#xff08;英语&#xff1a;Cloud storage&#xff09;的模式&#xff0c;即把数据存放在通常由第三方托管的多台虚拟服务器&#xff0c;而非专属的服务器上。今天就让我们来看看关于云陈存储的精华问答吧。1Q&#xff1a;云存储是如何分类的&#x…

mysql如何实现管理权限分离_基于SpringCloud+vue(ElementUI)+mySQL前后端分离设计之--搭建权限管理系统...

权限图&#xff1a;pom.xmlxsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">4.0.0com.serverauthority0.0.1-SNAPSHOTjarauthorityauthority project for Spring Bootorg.springframework.bootspring-boot-s…

刚刚,Python内幕被爆出!老码农:没控制住,心态已崩!

作为一名老码农&#xff0c;我的心这次凉透了&#xff01;事情起因很简单&#xff1a;前天我晚上正在全国最大的同性组织某Hub上浏览时候&#xff0c;发现这样的一条信息&#xff1a;Python 116K 超过 C、JS, 薪酬排行第一&#xff08;最大招聘网站Indeed.com数据&#xff09;噗…

vba上传文件到ftp服务器指定目录下面

vba上传文件到ftp服务器指定目录 脚本形式 文章目录1. 测试版本无校验&#xff1a;2. 测试版本有检验3. 文件不存在校验版本4. 文件不存在校验必填项校验版本1. 测试版本无校验&#xff1a; Sub 按钮1_Click() Dim i, str1, str2, str3, str4, str5, str6, str7, str8, str9, s…

分布式存储首选,浪潮商用机器FP5466G2服务器测评分析

戳蓝字“CSDN云计算”关注我们哦&#xff01;如今随着信息时代的到来&#xff0c;以云计算、大数据、人工智能为代表的新晋技术与应用实现了爆发式的增长&#xff0c;随之而来促生了原本存在于各个行业的大量业务应用中PB级&#xff0c;甚至EB级的海量版数据信息&#xff0c;这…

pipelines mysql_Scrapy爬取豆瓣图书数据并写入MySQL

介绍本篇涉及的内容主要是获取分类下的所有图书数据&#xff0c;并写入MySQL准备Python3.6、Scrapy、Twisted、MySQLdb等演示代码一、创建项目scrapy startproject BookSpider #创建项目scrapy genspider douban book.douban.com #创建豆瓣爬虫二、创建测试类(main.py)from scr…

独行速众行远,BitTitan携手世纪互联蓝云助力用户数据完美迁移

戳蓝字“CSDN云计算”关注我们哦&#xff01;近日&#xff0c;Saas解决方案提供商BitTitan宣布&#xff0c;将拓展与世纪互联蓝云的合作&#xff0c;双方将在中国的云服务市场上线BitTitan广受欢迎的MigrationWiz用户数据迁移套装方案。BitTitan是一家致力于让IT专业人员通过自…