在今年的上旬,有幸学习了李运华老师的《从0开始学架构》,碰巧最近参加技术群组织的ShardingSphere的源码的分享小组。所以想结合运华老师的学习方法结合我在项目中的经历复盘一下当时我是如何思考和学习ShardingSphere的。
在我介绍李运华老师的开源系统学习方法之前,我觉得我们应该了解一下何为学习金字塔理论。
美国学者、著名的学习专家爱德加·戴尔在1946年最先提出该理论,美国缅因州的国家训练实验室做过类似的研究,并提出了“学习金字塔”理论。
虽然我从各方信息了解到图中所示的数据并未通过严谨的实证研究推出,但是金字塔理论可以说是认知发展理论、信息加工理论、人本主义学习理论和建构主义理论在教学方面的具体化,通过运用金字塔理论,最终使学习到的知识向能力转化。
运华老师通过自身的学习和10多年在研发上的经验总结出的开源系统学习方法就是结合金字塔理论而成的方法论,通过运用这个学习方法使我们在开源系统的运用上做得更好。
老师在专栏中把学习方法分为以下5个步骤
目的
初步掌握基本信息、技术本质、应用场景
看文档、看文章
官方文档的Introduction和Get started
目的
熟悉基本使用,包括安装配置、架构模式
对照官方文档搭建简单的环境
研究命令行和配置项
目的
通过模拟案例掌握如何应用
模拟不同的业务场景,设计对应的方案,能写Demo的就写Demo尝试
结合自己的业务
目的
从技术深度和技术宽度两个维度来全方位的学习
看文档、看源码、看文章等
1. 链式学习法
2. 比较学习法
不懂对应的语言的别去看源码
先按照链式学习法学习相关的原理和方案,再去看源码是如何实现原理或者方案的
1. 不要逐行去看,看关键实现
2. 先看网上已有的文章
目的
通过分享帮助自己体系化和加深理解,增强记忆
写文章、培训、演讲
1. 梳理补充、提炼总结官方文档
2. 对比类似系统
通过官网我们可以知道
Apache ShardingSphere 产品定位为
Database Plus
,旨在构建多模数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。ShardingSphere 站在数据库的上层视角,关注他们之间的协作多于数据库自身。
连接
、增量
和可插拔
是 Apache ShardingSphere 的核心概念。
连接
:通过对数据库协议、SQL 方言以及数据库存储的灵活适配,快速的连接应用与多模式的异构数据库;增量
:获取数据库的访问流量,并提供流量重定向(数据分片、读写分离、影子库)、流量变形(数据加密、数据脱敏)、流量鉴权(安全、审计、权限)、流量治理(熔断、限流)以及流量分析(服务质量分析、可观察性)等透明化增量功能;可插拔
:项目采用微内核 + 三层可插拔模型,使内核、功能组件以及生态对接完全能够灵活的方式进行插拔式扩展,开发者能够像使用积木一样定制属于自己的独特系统。
定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
- 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
- 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
- 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。
即通过引入ShardingSphere-JDBC在项目中并进行初始化后我们既可以使用Apache ShardingSphere的增量功能,从官网提供文档来看,ShardingSphere-JDBC支持几乎目前市面使用的基于JDBC的ORM框架、数据库连接池和数据库。从具体实施者的角度来看,较好的兼容性的开源框架容易避开兼容性问题带来的工作延误。从架构师的角度来看,较好的兼容性可以方便日后对整个框架的拓展。
定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL(兼容 openGauss 等基于 PostgreSQL 的数据库)版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据,对 DBA 更加友好。
- 向应用程序完全透明,可直接当做 MySQL/PostgreSQL 使用;
- 适用于任何兼容 MySQL/PostgreSQL 协议的的客户端。
通过GitHub的发版信息我们可以知道目前Apache ShardingSphere的主要产品是ShardingSphere-JDBC和ShardingSphere-Proxy,ShardingSphere-JDBC 采用无中心化架构,与应用程序共享资源,适用于 Java 开发的高性能的轻量级 OLTP 应用; ShardingSphere-Proxy 提供静态入口以及异构语言的支持,独立于应用程序部署,适用于 OLAP 应用以及对分片数据库进行管理和运维的场景。通过ShardingSphere-JDBC和ShardingSphere-Proxy的混合使用,使我们在构建分库分表的系统之余,不需要花费更多的精力在研究如何对分库分表的数据进行访问。
运华老师的安装运行这个步骤对象适合是对可执行的应用进行了解,这里我就贴一下我在项目上线后自己尝试ShardingSphere-Proxy的内容配置,由于ShardingSphere在5.0之后对配置进行了修改,我这里贴出的是基于ShardingSphere-Proxy 5.0的运行尝试
apache-shardingsphere-5.0.0-shardingsphere-proxy
配置并成功启动shardingsphere-proxy
测试使用shardingsphere-proxy进行查询
22:34:46.247 [Connection-1-ThreadExecutor] INFO ShardingSphere-SQL - Logic SQL: select * from eshop_address where city_code=0
22:34:46.247 [Connection-1-ThreadExecutor] INFO ShardingSphere-SQL - SQLStatement: MySQLSelectStatement(limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
22:34:46.247 [Connection-1-ThreadExecutor] INFO ShardingSphere-SQL - Actual SQL: ds_0 ::: select * from eshop_address_0 where city_code=0 ORDER BY address_id ASC
22:34:46.247 [Connection-1-ThreadExecutor] INFO ShardingSphere-SQL - Actual SQL: ds_0 ::: select * from eshop_address_1 where city_code=0 ORDER BY address_id ASC
ShardingSphere-Proxy作为数据库中间件,从目前来看它的对标产品是MyCat,他的配置内容和ShardingSphere-JDBC基本一致,但是从官网了解到ShardingSphere-Proxy没有官方的集群方案,在实际业务使用中实现proxy端的高可用可能就需要额外的开发,我感觉公司没有到一定富裕的开发能力,ShardingSphere-Proxy可能会适合搭建用于给DBA管理数据库内容和内部给统计部门进行数据结构化分析。
更多情况下开源框架的运行和场景步骤模拟是同时进行的
2021-12-21 21:03:12.207 INFO 33418 --- [nio-8080-exec-1] ShardingSphere-SQL : Logic SQL: select a.address_id,a.user_id,a.address_name,
a.country_code,
a.phone,a.province_code,
a.city_code,
a.region_code,
a.detail,a.create_user_id,a.create_time,a.modify_user_id,a.modify_time
from eshop_address a
where a.city_code=?
and a.region_code=?
2021-12-21 21:03:12.207 INFO 33418 --- [nio-8080-exec-1] ShardingSphere-SQL : SQLStatement: MySQLSelectStatement(limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2021-12-21 21:03:12.207 INFO 33418 --- [nio-8080-exec-1] ShardingSphere-SQL : Actual SQL: db0 ::: select a.address_id,a.user_id,a.address_name,
a.country_code,
a.phone,a.province_code,
a.city_code,
a.region_code,
a.detail,a.create_user_id,a.create_time,a.modify_user_id,a.modify_time
from eshop_address_0 a
where a.city_code=?
and a.region_code=? ::: [0, 2]
通过事先配置的路由规则查找指定库指定表
在实际开发当中一般是多个项目使用同一个基础组件,因此在做架构演进的时候我们要考虑到对不同项目的影响,新追加的内容在完成新的需求下还要尽量少的影响旧项目,因此在实际把ShardingSphere-JDBC引入基础组件的时候不会像我演示代码那样直接重写datasource的初始化,而是通过@ConditionalOnProperty、@ConditionalOnBeand的方式来控制初始化。
ShardingSphere-JDBC是一款SDK的数据库中间件,在应用上已经满足当时我们需要对每个接入集团数据进行分库的需求,只要当我们在系统设计中对数据库设计加入集团区别标识字段,当查询的时候携带识别标识就能在查询内容的时候实现集团识别,从而拉取数据。而高可用方面因为他是SDK引入到服务当中,因此只要我们的服务实现了高可用,那它就天然是高可用的。
ShardingSphere-JDBC在项目中并进行初始化后我们既可以使用Apache ShardingSphere的增量功能,从官网提供文档来看,ShardingSphere-JDBC支持几乎目前市面使用的基于JDBC的ORM框架、数据库连接池和数据库。从具体实施者的角度来看,较好的兼容性的开源框架容易避开兼容性问题带来的工作中延误。从架构师的角度来看,较好的兼容性可以方便日后对整个框架的拓展。
几乎所有情况下我们在架构进行演进的时候都会使用成熟的开源系统,这就代表它肯定成功落地,互联网上会有对应的内容分享,如果没有互联网上的内容只能死啃源码了。
我们项目使用的ShardingSphere算是数据库方面比较火的中间件,因此视频还是文字都有比较多的内容,我们通过互联网的内容我们能很快的了解到ShardingSphere的分片引擎结构为解析引擎、路由引擎、改写引擎、执行引擎和归并引擎:
再通过我们在源码上的学习和交流群众的交流,我们可以得到一次SQL在路由引擎中源码
PartialSQLRouteExecutor
public RouteContext route(final LogicSQL logicSQL, final ShardingSphereMetaData metaData) {
RouteContext result = new RouteContext();
for (Entry<ShardingSphereRule, SQLRouter> entry : routers.entrySet()) {
if (result.getRouteUnits().isEmpty()) {
result = entry.getValue().createRouteContext(logicSQL, metaData, entry.getKey(), props);
} else {
entry.getValue().decorateRouteContext(result, logicSQL, metaData, entry.getKey(), props);
}
}
if (result.getRouteUnits().isEmpty() && 1 == metaData.getResource().getDataSources().size()) {
String singleDataSourceName = metaData.getResource().getDataSources().keySet().iterator().next();
result.getRouteUnits().add(new RouteUnit(new RouteMapper(singleDataSourceName, singleDataSourceName), Collections.emptyList()));
}
return result;
}
通过源码发现进行路由的时候,会根据我们的配置进行路由运算,举我们demo的例子为例它采用的是InlineShardingAlgorithm(基于行表达式的分片算法)得到目标库后,进行查询的时候就会通过目标库的的tag去映射出对应的读写分离数据库。
显然修改github上的源码重新打包是一种解决方案,但是我们通过学习知道ShardingSphere可以通过SPI实现拓展,下面我会通过实现一个可能的需求来进行展示。
这里有个很常见的需求就是提供的数据库可能性能不一样,在做读写分离的时候,希望读库的时候可以根据实际数据库性能进行加权的负载均衡。
目前我们通过分析源码可知目前框架只提供了轮询和随机两种负载均衡方式
因此我们需要通过在META-INF/services/org.apache.shardingsphere.readwritesplitting.spi.ReplicaLoadBalanceAlgorithm进行SPI来扩展我们自己的负载均衡方法,详细可以参考
这样可以用更优雅和兼容的方式来实现,也避免后续的版本升级会因为前任的暴力实现而带来太多的阻碍。
一般来说一个开源框架的使用进行到第三步就够了,为什么还有第四步,在我看来有两面:在公,如性能调优、特殊功能拓展一般只能通过公司内部实现,没有深入的了解是无法进行的,如果我没去了解ShardingSphere的SPI拓展,可能会绕很大的圈去实现它。在私,优秀的开源框架都拥有优秀的设计,我们通过深入学习这些框架能扩展自己的设计思路。
在教授他人的过程中,自己必定要真正掌握这个知识,还要有能力透过语言的呈现进行讲解,是知识向能力转化,因此我除了写下这篇博客以外我还写下了:
记开源系统落地-我是如何在工作中应用ShardingSphere-JDBC
第五步则是第四步的延伸,随着逐步深入的学习,我们能慢慢的勾勒出整个架构的全貌,当我们选择给组内进行培训和外部交流的时候,我们就更需要充分理解我们所使用的框架。最终使自己成为这个框架的专家。
运华老师的开源系统学习方法是一个不断迭代、不断深化的过程。在不同场景使用后,我们会提出各种猜想和问题,通过对源码和原理的学习我们可以解答这样的猜想和问题,通过在公司和博客上的分享,可以加深我们对系统的理解,通过周而复此的循环来提高我们技术的层次。希望在这样的学习循环中,我最终能成为独当一面的架构师。
参考:https://shardingsphere.apache.org/document/current/cn/overview/
文章浏览阅读5.4k次。./certbot-auto --nginx --nginx-server-root=/usr/local/nginx/conf_certbot 指定路径
文章浏览阅读3.2k次。java.util.zip.ZipException: error in opening zip file这个问题的字面意思是压缩包打不开,我这出现的问题是jar包损坏,打不开。linux系统可以使用命令判断jar 是否正常:jar -vtf xxx.jar查看jar归档目录[root@localhost classes]# jar -h非法选项: h用法: jar {ctxui}[vfmn0PM..._java.util.zip.zipexception: error in opening zip file
文章浏览阅读1.3k次。题链:https://ac.nowcoder.com/acm/contest/9925/C题意:求 。思路:首先,暴力的话就是枚举i,j。那么算法的话就很容易想到数位dp。看到&运算,肯定是二进制,那就是数二进制位。再看,因为要求i&j==0,那么i和j中每一位中都最多只能有一个1(每一位只能有00,01,10,3种情况);又因为log运算,那么i,j中最高位的1是第几位就是的值。那么,我们枚举每一个最高位(也就是枚举的值),然后数位dp算i&j==0的个数就行了
文章浏览阅读6.7k次。原文地址:https://blog.ch-wind.com/ue4-async-note/虚幻本身有提供一些对异步操作的封装,这里是对这段时间接触到的“非同步”的操作进行的总结。当前使用的UE4版本为4.18.2。在虚幻的游戏制作中,如果不是特殊情况一般不会有用到线程的时候。但是由于实际上虚幻内部是有着许多线程机制的。例如通常的游戏引擎中游戏线程和渲染线程都是独立的,相互之间会存在..._ue tfuture
文章浏览阅读1.2k次。在工作中需要用到curl 远程获取数据,但是访问速度太慢了,有时候需要10几秒到20秒,查了下原因,原来是DNS域名解析速度太慢了,所以,这里我们需要先获取抓取网站的域名的IP,然后再进行处理,经过将域名替换为对应的IP后速度大大的提高了,只用不到3秒就可抓取到数据。 请看示例: ..._提高curl -o 速度
文章浏览阅读4.2k次,点赞4次,收藏39次。LightGBM调参指导针对leaf-wise树的参数优化:num_leaves:控制了叶节点的数目。它是控制树模型复杂度的主要参数。 如果是level-wise,则该参数为2depth2depth,其中depth为树的深度。但是当叶子数量相同时,leaf-wise的树要远远深过level-wise树,非常容易导致过拟合。因此应该让num_leaves小于2depth2depth。在leaf-wise树中,并不存在depth的概念。因为不存在一个从leaves到depth的合理映射。 ..._lightgbm mgts
文章浏览阅读136次。https://www.biaodianfu.com/bpr.htmlhttps://www.jianshu.com/p/fd3081abf951https://www.jianshu.com/p/eb54c6a5d08bhttps://blog.csdn.net/qq_38861305/article/details/100942019_贝叶斯个性化推荐 可解释性
文章浏览阅读106次。链接:http://poj.org/problem?id=2761代码:31 struct Node { int l, r, sum; }T[MAXN * 40];32 int a[MAXN], root[MAXN], cnt;33 VI v;34 35 void update(int l, int r, int &x, int y, int po...
文章浏览阅读700次,点赞2次,收藏7次。基于百度飞桨的单/多人行人跟踪代码参考:GitHub - PaddlePaddle/PaddleDetection at release/0.2自己做了一些更改,下面是百度网盘链接:链接:https://pan.baidu.com/s/10UBq2TRtFGORs30P9VaZxg提取码:sdfo复制这段内容后打开百度网盘手机App,操作更方便哦一:百度飞桨的环境配置参考:飞桨PaddlePaddle-源于产业实践的开源深度学习平台二:运行demo:三:代码接口: tools->_百度飞桨跨镜头跟踪人
文章浏览阅读5k次。说在前面最近针对公司项目进行了iPad的适配,发现了很多有关屏幕旋转的适配,发现了一些有趣的问题.1.UICollectionView的itemsize的旋转自适应UIcollectionView在屏幕旋转的过程中,没有进行自动适配,也就是旋转的过程中,collectionView的UIcollectionViewDelegateFlowLayout并没有重新出发调用.解决方案:页面添加屏..._ios 旋转屏幕适配collectionview
文章浏览阅读651次。文章目录调度方式nodeName方式nodeSelect方式故障排除控制器DeploymentSatefulSetDaemonSetJobCronJob常规service和无头服务区别serviceheadless方式k8s配置管理SecretConfigMap调度方式调度方式用于将pod资源调度到相应的node上,可自动分配也可自己指定nodeName:用于将pod调度到指定node上(跳过调度器直接分配)nodeSelect:用于将pod调度到匹配label的node上nodeName方式_vim sts.yaml
文章浏览阅读556次。一. 给定一个入栈顺序,输出所有出栈顺序。我的做法是将入栈序列全排列,筛选出满足出栈要求的序列,如何判断是否满足要求呢?用数组out来记录需要判断是否满足要求的序列,数组enter记录入栈序列,用一个栈来模拟元素的入栈和出栈。如果栈顶和out对应位置元素相等就删除栈顶元素,否则将enter中的元素入栈,最后栈不为空就说明不满足要求。#include <bits/st..._已知出栈顺序判断可能的入栈顺序的算法