springBoot2集成shardingsphere4做读写分离并记录sql

 

本文记录springboot2集成shardingsphere4实现业务层读写分离,其余相关涉及组件 :mybatis-plus,hikari, postgresql , logback ,p6spy

1. pom文件引入shardingsphere4依赖      

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.1</version>
</dependency>

2.shardingsphere4相关配置项

 1 spring:
 2   shardingsphere:
 3     datasource:
 4       names: master,slave0,slave1
 5       master:
 6         type: com.zaxxer.hikari.HikariDataSource
 7         driver-class-name: com.p6spy.engine.spy.P6SpyDriver
 8 #        连接池配置项
 9         jdbc-url: jdbc:p6spy:postgresql://a:5432/bb
10         username: postgres
11         password: postgres
12         autoCommit: false
13         maximum-pool-size: 10
14         validation-timeout: 5_000
15         connection-timeout: 30_000
16         idle-timeout: 600_000
17         max-lifetime: 1_800_000
18       slave0:
19         type: com.zaxxer.hikari.HikariDataSource
20         driver-class-name: com.p6spy.engine.spy.P6SpyDriver
21         jdbc-url: jdbc:p6spy:postgresql://b:5432/bb
22         username: postgres
23         password: postgres
24         autoCommit: false
25         maximum-pool-size: 10
26         validation-timeout: 5_000
27         connection-timeout: 30_000
28         idle-timeout: 600_000
29         max-lifetime: 1_800_000
30       slave1:
31         type: com.zaxxer.hikari.HikariDataSource
32         driver-class-name: com.p6spy.engine.spy.P6SpyDriver
33         jdbc-url: jdbc:p6spy:postgresql://c:5432/bb
34         username: postgres
35         password: postgres
36         autoCommit: false
37         maximum-pool-size: 10
38         validation-timeout: 5_000
39         connection-timeout: 30_000
40         idle-timeout: 600_000
41         max-lifetime: 1_800_000
42 #        读写分离配置项
43     masterslave:
44       load-balance-algorithm-type: round_robin  # random
45       master-data-source-name: master
46       slave-data-source-names: slave0,slave1
47       name: ms
48     props:
49       sql:
50         show: true

3.p6spy相关配置项 (resources下创建spy.properties文件,内容如下)

 1 #开启模块sql记录和长时sql记录
 2 module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
 3 logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
 4 #自定义sql输出格式
 5 customLogMessageFormat=%(currentTime) | TIME\uFF1A %(executionTime) ms | SQL\uFF1A %(sql)
 6 #日志输出方式
 7 appender=com.p6spy.engine.spy.appender.Slf4JLogger
 8 excludecategories=info,debug,result,resultset
 9 deregisterdrivers=true
10 dateformat=yyyy-MM-dd HH:mm:ss
11 driverlist=org.postgresql.Driver
12 #开启长时sql记录
13 outagedetection=true
14 #触发长时记录时限
15 outagedetectioninterval=2

4.logback相关配置(resource文件夹下创建logback-spring.xml内容如下)

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <configuration>
  3 
  4     <!--日志格式应用spring boot默认的格式,也可以自己更改-->
  5     <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
  6 
  7     <!--定义日志存放的位置,默认存放在项目启动的相对路径的目录-->
  8     <springProperty scope="context" name="LOG_PATH" source="log.path" defaultValue="log"/>
  9     <springProperty scope="context" name="ZONE" source="quick.zone" defaultValue="default"/>
 10     <springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="app"/>
 11     <springProperty scope="context" name="LOGSTASH_URL" source="logstash.url" defaultValue="localhost:4560"/>
 12 
 13     <!-- ****************************************************************************************** -->
 14     <!-- ****************************** 开发环境日志 ************************************ -->
 15     <!-- ****************************************************************************************** -->
 16     <springProfile name="local">
 17         <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 18             <encoder>
 19                 <pattern>${CONSOLE_LOG_PATTERN}</pattern>
 20                 <charset>utf-8</charset>
 21             </encoder>
 22         </appender>
 23 
 24         <!-- 日志记录器,日期滚动记录 -->
 25         <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
 26 
 27             <!-- 正在记录的日志文件的路径及文件名 -->
 28             <file>${LOG_PATH}/${ZONE}-${APP_NAME}-local.log</file>
 29 
 30             <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
 31             <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
 32 
 33                 <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
 34                 <fileNamePattern>${LOG_PATH}/all/${ZONE}-${APP_NAME}-%d{yyyy-MM-dd}.%i-local.log</fileNamePattern>
 35 
 36                 <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
 37                     <maxFileSize>10MB</maxFileSize>
 38                 </timeBasedFileNamingAndTriggeringPolicy>
 39             </rollingPolicy>
 40 
 41             <!-- 追加方式记录日志 -->
 42             <append>true</append>
 43 
 44             <!-- 日志文件的格式 -->
 45             <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
 46                 <pattern>${FILE_LOG_PATTERN}</pattern>
 47                 <charset>utf-8</charset>
 48             </encoder>
 49         </appender>
 50 
 51         <!--默认所有的包以warn-->
 52         <root level="warn">
 53             <appender-ref ref="STDOUT"/>
 54             <appender-ref ref="FILE"/>
 55         </root>
 56 
 57         <!--ShardingSphere打印sql用-->
 58         <logger name="ShardingSphere-SQL" level="info"/>
 59         <!--p6spy打印sql-->
 60         <logger name="p6spy" level="info"/>
 61         <!--屏蔽getRowIdLifetime未实作警告-->
 62         <logger name="com.zaxxer.hikari.pool.ProxyConnection" level="error"/>
 63 
 64         <!--各个服务的包在本地执行的时候,打开debug模式-->
 65         <logger name="com.myproject" level="debug" additivity="false">
 66             <appender-ref ref="STDOUT"/>
 67             <appender-ref ref="FILE"/>
 68         </logger>
 69     </springProfile>
 70 
 71     <!-- ********************************************************************************************** -->
 72     <!-- **** 放到服务器上不管在什么环境都只在文件记录日志,控制台(catalina.out)打印logback捕获不到的日志 **** -->
 73     <!-- ********************************************************************************************** -->
 74     <springProfile name="!local">
 75 
 76         <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 77             <encoder>
 78                 <pattern>${CONSOLE_LOG_PATTERN}</pattern>
 79                 <charset>utf-8</charset>
 80             </encoder>
 81         </appender>
 82 
 83         <!-- 日志记录器,日期滚动记录 -->
 84         <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
 85 
 86             <!-- 正在记录的日志文件的路径及文件名 -->
 87             <file>${LOG_PATH}/quick/${ZONE}-${APP_NAME}-log-error.log</file>
 88 
 89             <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
 90             <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
 91 
 92                 <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
 93                 <fileNamePattern>${LOG_PATH}/quick/${ZONE}-${APP_NAME}-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
 94 
 95                 <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
 96                 命名日志文件,例如log-error-2013-12-21.0.log -->
 97                 <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
 98                     <maxFileSize>10MB</maxFileSize>
 99                 </timeBasedFileNamingAndTriggeringPolicy>
100             </rollingPolicy>
101 
102             <!-- 追加方式记录日志 -->
103             <append>true</append>
104 
105             <!-- 日志文件的格式 -->
106             <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
107                 <pattern>${FILE_LOG_PATTERN}</pattern>
108                 <charset>utf-8</charset>
109             </encoder>
110 
111             <!-- 此日志文件只记录error级别的 -->
112             <filter class="ch.qos.logback.classic.filter.LevelFilter">
113                 <level>error</level>
114                 <onMatch>ACCEPT</onMatch>
115                 <onMismatch>DENY</onMismatch>
116             </filter>
117         </appender>
118 
119         <!-- 日志记录器,日期滚动记录 -->
120         <appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
121 
122             <!-- 正在记录的日志文件的路径及文件名 -->
123             <file>${LOG_PATH}/quick/${ZONE}-${APP_NAME}-log-all.log</file>
124 
125             <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
126             <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
127 
128                 <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
129                 <fileNamePattern>${LOG_PATH}/quick/${ZONE}-${APP_NAME}-all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
130 
131                 <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
132                 命名日志文件,例如log-error-2013-12-21.0.log -->
133                 <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
134                     <maxFileSize>10MB</maxFileSize>
135                 </timeBasedFileNamingAndTriggeringPolicy>
136             </rollingPolicy>
137 
138             <!-- 追加方式记录日志 -->
139             <append>true</append>
140 
141             <!-- 日志文件的格式 -->
142             <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
143                 <pattern>${FILE_LOG_PATTERN}</pattern>
144                 <charset>utf-8</charset>
145             </encoder>
146         </appender>
147 
148         <!-- 日志记录器,日期滚动记录 纪录TAM日志-->
149         <appender name="FILE_TAM" class="ch.qos.logback.core.rolling.RollingFileAppender">
150 
151             <!-- 正在记录的日志文件的路径及文件名 -->
152             <file>${LOG_PATH}/quick/${ZONE}-${APP_NAME}-log-tam.log</file>
153 
154             <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
155             <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
156 
157                 <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
158                 <fileNamePattern>${LOG_PATH}/quick/${ZONE}-${APP_NAME}-tam-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
159 
160                 <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
161                 命名日志文件,例如log-error-2013-12-21.0.log -->
162                 <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
163                     <maxFileSize>10MB</maxFileSize>
164                 </timeBasedFileNamingAndTriggeringPolicy>
165             </rollingPolicy>
166 
167             <!-- 追加方式记录日志 -->
168             <append>true</append>
169 
170             <!-- 日志文件的格式 -->
171             <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
172                 <pattern>${FILE_LOG_PATTERN}</pattern>
173                 <charset>utf-8</charset>
174             </encoder>
175             <!-- 此日志文件只记录error级别的 -->
176             <filter class="ch.qos.logback.classic.filter.LevelFilter">
177                 <level>error</level>
178                 <onMatch>ACCEPT</onMatch>
179                 <onMismatch>DENY</onMismatch>
180             </filter>
181         </appender>
182 
183         <!-- 日志记录器,日期滚动记录 纪录AUDITLOG日志-->
184         <appender name="FILE_AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender">
185 
186             <!-- 正在记录的日志文件的路径及文件名 -->
187             <file>${LOG_PATH}/auditlog/${ZONE}-${APP_NAME}-log-auditLog.log</file>
188 
189             <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
190             <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
191 
192                 <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
193                 <fileNamePattern>${LOG_PATH}/auditlog/${ZONE}-${APP_NAME}-auditlog-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
194 
195                 <!-- 除按日志记录之外,还配置了日志文件不能超过10M,若超过10M,日志文件会以索引0开始,
196                 命名日志文件,例如log-error-2013-12-21.0.log -->
197                 <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
198                     <maxFileSize>10MB</maxFileSize>
199                 </timeBasedFileNamingAndTriggeringPolicy>
200             </rollingPolicy>
201 
202             <!-- 追加方式记录日志 -->
203             <append>true</append>
204 
205             <!-- 日志文件的格式 -->
206             <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
207                 <pattern>${FILE_LOG_PATTERN}</pattern>
208                 <charset>utf-8</charset>
209             </encoder>
210             <!-- 此日志文件只记录info级别的 -->
211             <filter class="ch.qos.logback.classic.filter.LevelFilter">
212                 <level>info</level>
213                 <onMatch>ACCEPT</onMatch>
214                 <onMismatch>DENY</onMismatch>
215             </filter>
216         </appender>
217 
218         <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
219             <destination>${LOGSTASH_URL}</destination>
220             <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" />
221         </appender>
222 
223 
224         <!--记录到文件时,记录两类一类是error日志,一个是所有日志-->
225         <root level="warn">
226             <appender-ref ref="STDOUT"/>
227             <appender-ref ref="FILE_ERROR"/>
228             <appender-ref ref="FILE_ALL"/>
229         </root>
230 
231         <logger name="com.myproject" level="info"/>
232         <!--ShardingSphere打印sql用-->
233         <logger name="ShardingSphere-SQL" level="info"/>
234         <!--p6spy打印sql-->
235         <logger name="p6spy" level="info"/>
236         <!--屏蔽getRowIdLifetime未实作警告-->
237         <logger name="com.zaxxer.hikari.pool.ProxyConnection" level="error"/>
238     </springProfile>
239 
240 </configuration>

5.集成结果

springBoot2集成shardingsphere4做读写分离并记录sql

 

 

 通过以上日志观察发现已经实现了业务层面读写分离和读库的轮询负载策略

springBoot2集成shardingsphere4做读写分离并记录sql

 

 

 通过以上日志发现已经实现了线上环境的完整sql记录,至此已达到预期效果,集成完毕

6.问题总结

  1.从数据层方面shardingsphere4并没有实现主从库的数据同步,在其他方案的数据同步过程中主从数据不一致导致的数据差异是否满足应用场景还需具体评估.

  2.本实例数据库采用postgres,目前最新版本的postgres数据库驱动也没有实现getRowIdLifetime()方法,shardingsphere4缓存数据源元数据的时候会去调用该方法,

驱动程序会抛出一个方法未实作的异常从下面代码可见框架捕获后不做处理并缓存该项为UNSUPPORTED,但是因为实例集成hikari连接池,hikar的ProxyConnection类会抛出一个一个警告如下图二,看起来像是项目启动报错,但实际并不影响,程序运行,因此在输出日志中将项屏蔽,具体配置在上面logback中

 springBoot2集成shardingsphere4做读写分离并记录sql

警告:

 

 

 springBoot2集成shardingsphere4做读写分离并记录sql

 

 3.logback的配置中root节点默认开启warm级别日志,要想支撑 shardingsphere 和p6spy记录sql需要单独配置相应节点,开放对应日志级别,因 shardingsphere 打印出的不完整sql,除了查看数据库路由外并没有太大用处,而本项目当前并不关心数据库路由,因此将对应配置项设为false,并集成p6spy完成完整的sql记录

4.配置项中的数据库url连接项名称视具体连接池可能会有不同,本实例用连接池该名为jdbc-url,有些连接池叫url

7.部分源码分析

springBoot2集成shardingsphere4做读写分离并记录sql

 

该主键的入口类,实现了EnvironmentAware接口,在DataSoureAutoConfiguration之前被执行对dataSource经常了包装处理用于支撑该框架的功能,下图为datasource实例化过程,该方法的第一个入参dataSourceClassName为配置项的type所以对连接池的配置项需要和type放在同一级,如文章开始配置项所示.

springBoot2集成shardingsphere4做读写分离并记录sql

 

 本实例只关心主从分离,其他源码部分相关类:

springBoot2集成shardingsphere4做读写分离并记录sql

 

 

以上,为全部内容,后期发现问题再做补充.

springBoot2集成shardingsphere4做读写分离并记录sql

上一篇:css 盒模型


下一篇:Centeros 7.6最小化安装(Linux系统安装)