RDS MySQL Java 开发实战 ——义泊

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
简介: RDS MySQL Java 开发实战——义泊

内容简要:

一、深入浅出ORM框架MyBatis

二、连接池框架剖析和最佳实践

三、Java应用性能问题诊断技巧

 

 

一、深入浅出ORM框架MyBatis

(一)为什么要选MyBatis

image.png

在以前是直接用JDBC进行数据库查询,优点是简单直接,缺点是开发效率低。用JDBC写程序,需要大量手工写代码,代码重复率较高,后来逐渐演化出ORM框架。

ORM框架最早期有Hibernate以及JPA规范,Hibernate能够屏蔽底层数据库差异,自动根据SQL语言生成对应底层不同数据库的方言,缺点是对关联查询支持与动态SQL能力不太友好,很难写出高效SQL

国内目前流行的是轻量级MyBatis,对动态SQL以及关联查询的支持性较高,缺点是因为它绑定一个DB,手写SQL还要动态拼接,很难从一个DB自由的切换到另外一个DB,但由于平时很少切换DB,因此问题不是很大。

 

(二)MyBatis基本概念介绍

image.png

MyBatis主要分为三层:接口层,核心层与基础层。

l  接口层

是通过提供的API作为数据库进行增///查,都是MyBatisAPI

l  核心层

Ø  SQL预处理、SQL执行、结果映射。

1)  SQL预处理:是对代码里的变量进行绑定,以及动态SQL生成;

2)  SQL执行:是把生成好的SQL,通过JDBC驱动,传到对应的DB里执行,而且要负责网络通信的部分;

3)  结果映射:是把数据库返回的结果从关系型数据转换成Java对象数据。

l  基础层

Ø  包括日志、事务管理、缓存、连接池、动态代理、配置解析。

1)  日志:是做框架里面的日志输出以及SQL语句输出;

2)  事务管理:是对 JDBC事物、数据库事物做管理;

3)  缓存:能够把结果集缓存在JVM的内存内部。优点是比较快,缺点是会占用堆内存。有条件的情况下,建议用户多使用分布式缓存;

4)  连接池:能够加速查询,提高性能;

5)  动态代理:在用MyBatis编程时,核心是通过接口执行数据库查询。而Mapper接口本身是没有实现的,实现是在或注解来配置SQL语句。动态代理会在运行时生成代理,当调用Mapper接口时,转换成实际的SQL语句;

6)  配置解析:因为MyBatis里面有存在大量配置,需要配置新模块,读取XML配置,并把它映射为配置属性。

 

(三)MyBatis0开始搭建工程

工程的搭建主要包括三部分:技术选型,项目依赖和工程结构。

1.技术选型

image.png

0开始搭建MyBatis工程,使用MyBatis没有意义。

如上图所示,现在主流是用Spring框架做结合,还有底层有连接池也要去做结合。最新的选型是Spring-boot2,需要开发Web工程,选择Spring-Webmvc框架,持久层或IRM映射层用MyBatis框架,连接池选择HikariCPHikariCPSpring-boot2的连接池,数据库使用RDS MySQL,也是国内比较流行的数据库。

有了以上选型之后,可以通过Spring官方网站上面的网站连接:“https://spring.io/quickstart”填入相关信息,就可以生成框项目模板。模板下载之后在ID里面打开导入项目,就有开始工作的项目模板。

 

2.项目依赖:

image.png

第一部分依赖:“spring-boot-starter”,依赖的作用是自动管理开始spring-boot项目的默认依赖,已经集成在Starter里面了。

第二部分依赖:用到了Spring-webmvc,是最新的2.4.1版本。

第三部分依赖:因为用到MyBatis,所以还需要依赖MyBatis starter。需要注意的是MyBatis并没有Spring官方的Starter,而是MyBatis社区提供的 MyBatis–spring-boot-starter

第四部分依赖:JDBC实现,“mysql-connector-java”因为JDBC是一套规范API,具体实现由各个数据库的厂商实现。

第五部分依赖:Spring-boot-starter框架测试部分。

第六部分依赖:为了减少代码量,还用到了Lombok

 

3.工程结构

image.png

上图为工程结构图,从上往下看:

l  1层:控制器层Controller,这里有一个自己的控制器。

l  2层:Mapper,主要是数据库增///查的接口。

l  3层:Model层,主要是在Java里面的对象定义。

l  4层:Service层,包括 API层和Impl层。

API层主要是接口的定义; Impl层主要是对接口的实现。

在接口里面调用Impl层,或者调用业务层实现业务逻辑组装和编排。

l  5层:是Java应用的启动入口。选择用XML方式配置MyBatis,所以在Resource目录里面,需要增加Mapper目录,mapper里面放入StaffMapper文件。

l  6层:是Spring的配置文件,还有Log4j配置文件,还有Mybatis配置文件。Mybatis配置的也可以通过编程的方式实现。

l  7层:有Pom文件。

通过以上操作,从0开始搭建的MyBatis工程就完成了。当工程启动后,在浏览器里面输入“http://localhost:8001/query?name=yanglong”链接,这里的端口还有路径都是自己定义的,可以验证工程是否正常运作。

 

二、连接池框架剖析和最佳实践

(一)为什么要用连接池?

image.pngl

不用连接池会存在以下问题:

1)如果不用连接池,每一次查询都需要建立连接,有两层握手。第一层是TCP层的握手,第二层是 MySQL协议握手。两层协议大概需要有多个TCP数据包,这些都需要时间,在数据库内部还需要处理,建立连接是费时间的操作;

2)对于当代的应用来说,应用服务器是很多台数据库,服务器相比之下可能少一些。大量应用服务器会存在一个问题,在业务流量高峰期存在对DB的连接,而DB能够承载的连接数有限。所以说如果不用连接池,那么这个连接的数量就不受控制,导致DB性能严重降低;

3)如果不用连接池,意味着每次执行SQL语句时,都需要创建TCL链接和关闭TCL链接,而关闭动作是在应用端完成,导致应用服务器上存在较多摊位状态的TCP连接。目前状态的连接数达到一定数量之后会引起应用问题,例如端口不够用。

 

l  用连接池的优点:

1)不用每次都建立连接,而是直接从连接池里取连接,性能更佳;

2)连接池可以控制连接数量,以及当连接出现问题时,连接池能够去自动探测连接是否存活,如果连接中断,连接池会自动重建;

比如应用使用RBSMySQL,需要对MySQL的实例进行配置变更。如升规格,提高磁盘空间,遇到问题者压力大时,希望能够重启MySQL,有了连接池就能够自动处理好这些问题。

3)连接池能够对连接进行灵活的管理,对连接池配置与连接池状态监控,看到连接池里面的各种连接数量和性能指标。

 

(二)连接池架构


image.png

连接池架构分为:接口层、核心层、基础层

l  接口层:对于MyBatis是从连接池里获取连接,连接用完之后关闭,调用连接的Close归还连接

 

l  核心层:负责并发控制、连接控制、异常处理。

1) 并发控制:连接池里的连接数量有限,应用里面的线程数量多于连接池的连接数量。

第一种情况,当连接池里的连接都处于活跃状态时,下一个请求,想要继续得到连接需要等待,因为数量有限,需要排队。

第二种情况,同一个链接,不能分配给多个线程,否则可能会开启事物。对同一个连接进行多次开启事务,会引起事故的混乱。

2) 连接控制:需要能够动态调整连接池大小,同时连接池保证连接池里面的连接数量在期望范围内。

3) 异常处理:出现异常时,比如底层数据库重启,网络中断,或者连接里面发生了协议层引擎层面错误,连接已经不能再使用,这个时候连接池自动处理这些问题,将连接关闭。

 

l  基础层:包括配置管理、监控、定时任务、日志、字节码操纵。

1) 配置管理:是连接池里面有很多的配置项,虽然常用的不多,但是可配置的点很多,需要进行解析管理。

2) 监控:连接运行时需要统计和监控,最好能够提供查看的页面。

3) 定时任务:连接池里连接数量超过一定的程度,释放空闲连接,是通过定时任务完成。

4) 字节码操纵:Java框架里面会存在大量的字节码操纵,动态生成代理,增加业务逻辑。

 

(三)Druid最佳实践

1.参数配置

image.png

如上图所示,常用配置包括:

1)  Max-active:指的是连接池里允许的最大活跃连接数,这个值根据应用实际情况调整。

2)  Min-idle:关掉多余连接,保留有效连接,节省数据库的资源,这个值根据应用实际情况调整。

3)  Max-wait,指应用线程等待超时。可以配几秒范围,根据业务应用实际情况进行判定。

4)  Validation-query,指的是连接池探测当前连接是否是健康的SQL语句。Druid最新版GDP驱动,调用Ping命令,如果GDP比较新,不会发SQL语句过去,而是发Ping命令。

5)  Validation-query-timeout,指的就是探测超时的时间。

6)  Test-on-borrow指连接从连接池里取出时,连接池是否需要对连接进行健康探测。建议关闭False

7)  Test-on-return,建议关闭False

8)  Test-while-idle,指的是控制,当连接处于空闲状态时,是否需检测连接的健康状态。建议打开True

9)  Time-between-eviction-runs-millis指的是触发空闲连接健康探测阈值,需要跟上面的Test-while结合起来。

10)Remove-abandoned,泄露连接强制回收,默认是False关闭。

11)Remove-abandoned-timeout,指的是强制回收的触发时间阈值。配置时间不要太短,因为业务长时间使用连接,所以超时时间要比业务实际合理时间要高。配置参数单位是“秒

12)Log-abandoned,指的是关闭被泄露连接时输出堆栈。当一个连接被探测为连接线路并且强制关闭的时候,是否要在日志里面输出连接获取连接的现场的对账,跟Remove结合使用。

image.png

如上图所示,当用户开启了空闲连接的健康探测时,在Druid的源码内部会出发怎么样的逻辑?

入口是MyBatis连接Druid时,getConnectionDirect是一个循环,在循环里从连接池里取一个空闲连接,当探测空闲连接健康开关开启时,Druid会去检测连接的空闲时间是否超过下面配置的阈值。

如果超过了,循环会发起一个连接的健康探测。如果探测出来连接有问题,Druid会直接把连接关闭。在循环里面,会回到循环开头,从连接池里再拿一个连接,直到拿到一个可用的连接,如果连接池里所有的连接都有问题,会重新创建连接.

 

2.监控

Druid的最佳实践做监控可以开启Spring,在配置中开启Delivery的监控选项,就会有一个内部维护状态。

image.png

同时基于Web的页面管理页面可以去监控连接词的运行状态。如上图所示,可以查看连接时的配置参数、版本、内路径,也可以查看连接实名的连接数、 SQL监控、C线监控、结成API,通过API可以拿到这些监控数据。

除此以外,通过JMX直接连到应用内部,查看登录到内部一些JMX对象的一些属性,如图内有些参数是可以修改的,有些只能看的还有一些操作,一些API可以去调用,因此JMX是较为强大的。

 

3.连接泄露诊断

l  现象

1)  正常请求拿不到连接报错;

2)  响应时间增大;

3)  应用不可用;

l  原因

1)连接被取出后没有正常归还,导致连接长时间被占有但没有使用;

2)一般都是代码问题;

l  解决办法

1)开启连接池泄露诊断;

2)修改代码;

 image.png

如上图两行日志,连接词里的连接全部被应用取走之后,新的应用与新的请求去取连接的时候就会得不到连接造成超时报错。一旦连接式的连接全部泄露,后续所有的请求都会因拿不到连接而报错。

可以通过在Spring的配置文件里面增加Druid的连接线路的参数。开启之后,当出现连接线路时,Druid会在日志里面打印出被泄露出去的线程,在取得连接的对账,可以直接看到是什么的业务代码,在什么情况下去拿了链接而没有归还,有助于定位问题。

 

 

三、Java应用性能问题诊断技巧

应用性能问题的诊断主要从三个方面:内存、CPU、网络

 

(一)内存

1.  内存

l  现象

1)OutOfMemoryError: Java heap space

2)频繁FULL GC

l  原因

1)内存泄露;

2)堆大小配置不合理;

l  解决方法

1)jvisualvm

2)jstat

3)jmap

4)mat

image.png

如上图所示,这段日志是当出现内存耗尽的时候,结果会报出来一些错误,应用会出现频繁的FULL GC

 

2.内存-JMX

image.png

诊断结内存的问题的方法:

可以打开JMX通过启动参数以-D开头这4个参数进行远程连接,连接之后可以看到最大堆的大小以及实际已经使用的情况。

 

3.内存-Jmap

同时通过JMX对堆进行一个Dump,文件会在Jvm运行所在主机的对应的目录上。

image.png

image.png

第二种是 Jmap-heap2780进程号,可以看到Jmap的堆的最大大小是512兆,同时看到老年代的使用情况是78%。通过命令把Jmap的堆内存Dump到文件中做后续分析。通过命令提示正在进行Dump,完成后会有一个Heap Dump File Created日志。

MAT打开堆的Dump文件,然后用内存线路分析模式,通过结果可以看到 Controller里面有大量的对象,MAT的下载地址https:/www.eclipse.org/mat/

 

4.内存-结合代码确认问题

image.png

确认最终的问题,打开 MAT打开堆的Dump文件之后,通过内存线路的分析,可以找到MyController下的历史对象,里面存在大量字符串,每个字符串的大小约为2M,大概有100个,占用了268兆,可以看到具体的字符串的内容。

结合代码,看到在代码中第63行申请了一个1M长度,2M字节大小的内存,并且把内存放到一个全局的静态变量中进行应用,所以JC无法回收,因为是一个强应用无法回收,否则将导致内存泄漏。

通过Jmap把堆Dump出来,再通过MVP工具对内存进行分析,找到占用内存的对象,再通过对象里的一些引用关系,就能够找到代码里面创建对象,找到出现问题的代码,完成内存的定位。

 

(二)CPU

CPU问题定位:

l  现象

1)应用响应缓慢;

2Java进程CPU占用高;

l  原因

1)存在大量消耗CPU的逻辑;

2)循环;

3)复杂计算;

l  解决方法

1)Top

2)Jvisualvm

3)Async-profiler

 

1.CPU-JMXJstack

image.png

如上图所示案例,一个一核的主机,CPU使用率接近100%,主机的负载达到了6点多,Java进程的CPU使用率可以到99%,通过选择JMX或者Jstack

JMX连上去之后去检查每个线程是否在执行,这里通过JMX可以看到线程池1里的线程号1~6在长期的运行,因此这可能就是问题线程。

同时可以通过Jstack查看Jvm里面每个现场的堆栈,但是通过Jstack有一个缺点就是当应用里面线程非常多的时候,Jstack的结果会非常大。

 

2.CPU-Async-Profiler

通过使用Async-profiler下载对应平台已编译好的代码,解压后找到对应的Java进程,通过这一串命令,对Java进程做一个系统剖析,剖析完之后会生成一个火焰图,通过火焰图能够准确的看到应用的热点代码。

l  这里对上列参数做一个说明:

增加了-e itimer后,会不依赖perf_events,只剖析JVM内一般就足够;

-d 10 表示剖析持续10秒,可以根据实际情况调整;

最后的3141Java进程的pid

image.png

通过生成的火焰图之后,用浏览器打开可以看到里面有6个线程长期霸占CPU。火焰图从上往下看,下面的方法是处于栈底的,上面的方法是属于栈顶的,栈顶的方法就是正在执行的方法,而栈顶上面的最长的方法就是占用CPU最多的方法,所以可以看到这里有6个线程,里面有6个栈,每个栈上都正在执行方法在消耗CPU

image.png

结合上图代码,通过堆栈来对应到源码。可以看到,通过JMX可以找到可疑的线程,通过Async-profiler可以生成火焰图,帮助用户直接定位到存在性能问题的线程以及它的堆栈,通过堆栈就用源码找到真正有问题的代码。

 

(三)网络

1.常用命令

l  网络问题包含以下常用命令:

1)查看当前主机IPip a

2)查看当前主机名:hostname

3)检查目标IP是否可达:ping

4)检查目标端口是否可达:telnet

5)查看网卡:ifconfig

6)查看路由表:route n

7)查看从当前主机发往目标主机中间会经过哪些路由:traceroute i

8)查看当前主机的网卡流量:iptraf-ng

9)查看以IP为单位的网络流量排名:iftop n

10)    查看当前主机上监听的端口:netstat tpnl

11)    查看当前主机上的TCP连接:netstat tpn

 

2.TCP状态机

image.png

TCP状态机是TCP连接的核心部分,只有深入理解TCP状态机,才能灵活运用TCP的命令与工具,以及理解输出的结果与意义。

 

3.TCP状态说明:

CLOSED:表示当前连接已经关闭。

LISTEN:表示当前正监听中,随时准备接受连接请求。

SYN_SENT:表示已经发送出建立TCP连接的数据包,等待对方回应。

SYN_RECVD:表示接受到了建立TCP连接的数据包,准备给对方发送SYN + ACK

ESTABLISHED:表示已经建立TCP连接。

FIN WAIT-1:表示主动关闭连接的一方已经发出了FIN包。

CLOSE WAIT:表示被动关闭的一方收到了FIN包。

FIN WAIT-2:表示主动关闭的一方收到了FINACK包,等待对方发出的 FIN包。

LAST ACK:表示被动关闭的一方发出了FIN包,开始等待对方发出ACK

TIMED WAIT:表示主动关闭的一方已经发出了ACK,此时主动关闭的一方要等待2Maximum segment lifetime,在此期间,任何因为网络延迟或者拥堵而未及时到达的包将会被丢弃,以防止下一个连接收到了上一个连接的包。

 

2.实战的场景

a.配置问题引起的应用阻塞

image.png

现象是一段Python(其它语言相同)程序会阻塞,应用僵死。

诊断:

可以看到Python程序在等待主机192.168.1.1ACK,而这个主机根本就不存在因此无法访问。再结合目标端口是80,定位到是程序HTTP请求的目标主机错误。

 

b.某个数据库的连接数暴涨,想查到连接来源

可以看到,来自10.0.3.15的连接数达到了999个,结合代码就可找到问题。

 

c.线上应用没有打印SQL到日志中,DB也没有开审计日志,如何能看到SQL信息?

image.png

可以在应用服务器执行tcpdump-i any表示监听任意网卡,port 3310表示去dump3310端口,-tttt表示在每个包前面增加一个时间戳,-nn表示不对端口和IP进行反向域名解析,-A表示以应用层的方式输出日志,-s0表示Buffer的控制。

通过这个命令,从网络上可以清晰的看到真实的SQL语句,这对于排查问题非常有帮助。

 

d.传说中的TCP3次握手和4次挥手,到底是什么样

命令:tcpdump -i any port 3310 -tttt -nn -X -s0

image.png

如上图所示,用户还可以通过Tcpdump来查看3次握手和4次挥手的网络数据。上图最上方三个包就是我们说的三次握手,它能够去建立TCP连接,建立成后MySQL会向客户端发送提示输入密码的文字,同时客户端会向MySQL客户端发送一个响应,表示收到数据包。

如果这个时候关闭连接就会产生4次挥手,分别是用户客户端向MySQL端发送一个关闭连接包文,MySQL会马上响应一个ACK,同时发出一个关闭连接包文,用户客户端也向MySQL响应一个ACK,这就是传说中TCP3次握手和4次挥手。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2天前
|
IDE Java 开发工具
Spring Boot:加速Java后端开发的现代化利器
在当今快速迭代的软件开发环境中,Spring Boot 已成为Java后端开发领域的首选框架。作为Spring家族的一员,它以“约定优于配置”的设计理念,极大地简化了传统Spring应用的配置和部署过程,让开发者能够更加专注于业务逻辑的实现。本文将探讨Spring Boot的核心优势,并通过一个简单的示例展示如何快速启动一个基于Spring Boot的Java Web应用。
14 1
|
3天前
|
Java
Java开发唯一性校验技巧
Java开发唯一性校验技巧
17 2
|
3天前
|
Java easyexcel
java开发excel导入导出工具类基于EasyExcel
java开发excel导入导出工具类基于EasyExcel
13 1
|
18小时前
|
缓存 JSON Java
使用Java进行RESTful API开发的最佳实践
使用Java进行RESTful API开发的最佳实践
|
1天前
|
设计模式 Java 开发者
Java中的代码优雅重构实战
Java中的代码优雅重构实战
|
1天前
|
缓存 Java 测试技术
Java中的Web服务开发与优化技巧
Java中的Web服务开发与优化技巧
|
1天前
|
移动开发 小程序 关系型数据库
java+ IDEA+ Uniapp+ mysql医院3D智能导诊系统源码
这是一个基于Java、IDEA、Uniapp和MySQL的医院3D智能导诊系统,采用Springboot后端框架和Redis、Mybatis Plus、RocketMQ等技术。系统通过对话式交互,精准推荐就诊科室,解决患者挂号困扰。它还具备智能预问诊功能,提升诊疗效率和准确性,确保医生能快速了解患者详情。此系统还支持小程序和H5,方便患者使用。
7 0
|
1天前
|
Java API 开发者
深入理解APDU协议与Java开发
深入理解APDU协议与Java开发
5 0
|
1天前
|
存储 开发框架 网络协议
深入了解Java中的嵌入式开发
深入了解Java中的嵌入式开发
4 0
|
1天前
|
存储 安全 Java
基于Java+MySQL停车场车位管理系统详细设计和实现(源码+LW+调试文档+讲解等)
基于Java+MySQL停车场车位管理系统详细设计和实现(源码+LW+调试文档+讲解等)

相关产品

  • 云数据库 RDS MySQL 版