canal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费.
版本:canal
1.1.6MySQL
8.0 +oracle
更新历史
无
canal 同步 mysql 到 oracle
主要步骤
开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式,my.cnf 中配置如下
1 | [mysqld] |
执行成功可登陆MySQL中查看
1 | show variables like '%log_format%'; |
授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant
1 | CREATE USER canal IDENTIFIED BY 'canal'; |
将 canal.deployer的压缩包安装到 /data/canal/canal.deployer/
目录下,
主要配置 conf/canal.properties
conf/example/instance.properties
conf/canal.properties
1 |
|
conf/example/instance.properties
xx都需要根据实际替换
1 | # ----------- 监听的数据库地址 修改成自己的 |
清理
修改配置后, 注意清除 /conf/example
目录下 meta.bat
启动 sh bin/startup.sh
关闭 sh bin/stop.sh
重启 sh bin/restartup.sh
启动成功后,类似如下日志logs/canal/canal.log
1 | [main] INFO com.alibaba.otter.canal.deployer.CanalStarter - ## start the canal server. |
logs/example/example.log
1 | [main] INFO c.a.otter.canal.instance.spring.CanalInstanceWithSpring - start CannalInstance for 1-example |
将 canal.adapter 的压缩包安装到 /data/canal/canal.adapter/
目录下,
主要配置 conf/application.yml
conf/rdb
添加对应的数据表配置
如果不使用远程配置, 把 conf/bootstrap.yml
全体注掉
总配置文件 conf/application.yml
1 | # --- 服务器端口 , 不要和其它服务冲突 |
最简单的处理, 将受到的变更事件通过日志打印的方式进行输出, 如配置所示, 只需要定义name: logger即可
1 | outerAdapters: |
目前内置支持的数据库列表:
MySQL
Oracle
PostgresSQL
SQLServer
理论上jdbc的数据库都可以。
conf/rdb
目录下, 对应上面的 key: oracle1, oracle2
test_oracle1
1 | dataSourceKey: defaultDS # 源数据源的key, 对应上面配置的srcDataSources中的值 |
test_oracle2
1 | dataSourceKey: defaultDS |
Apache ShardingSphere
Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈。Spring集成Apache ShardingSphere 是一套目前比较好的分库分表的方案。
Apache ShardingSphere JDBC 目前只支持同构数据库,本文通用自定义数据源实现异构数据库(spring boot + jpa + oracle + mysql)的分库分表。
版本:spring boot
V2.6.1Apache ShardingSphere
V5.1.0
更新历史
无
Apache ShardingSphere JDBC 目前只支持同构数据库, 可通用自定义数据源实现异构数据库(oracle + mysql)的分库分表。
以 oracle 数据库 作为 ShardingSphere JDBC 支持的主数据库。
主要步骤:
DataSource
(javax.sql.DataSource)EntityManagerFactory
(javax.persistence.EntityManagerFactory)EntityManager
( javax.persistence.EntityManager)TransactionManager
(org.springframework.transaction.TransactionManager)JdbcTemplate
(org.springframework.jdbc.core.JdbcTemplate)1 | <parent> |
1 | //使用ShardingSphere的分布式管理 |
Apache ShardingSphere 的数据源作为主DataSource
1 |
|
优先数据源
1 |
|
其他数据源
1 |
|
1 | spring: |
主数据源
和普通jpa 一样, 无区别
其他数据源
1 |
|
JSR-303 Validation
JSR-303 是 JAVA EE 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。
本文以 spring boot
V2.4.6 版本为例说明如何使用。
更新历史
无
常用的
空检查@Null
验证对象是否为null@NotNull
验证对象是否不为null, 无法查检长度为0的字符串@NotBlank
检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.@NotEmpty
检查约束元素是否为NULL或者是EMPTY.
Booelan检查@AssertTrue
验证 Boolean 对象是否为 true@AssertFalse
验证 Boolean 对象是否为 false
长度检查@Size(min=, max=)
验证对象(Array,Collection,Map,String)长度是否在给定的范围之内@Length(min=, max=)
验证约束字符串是否包含在最小和最大之间。
日期检查@Past
验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期@Future
验证 Date 和 Calendar 对象是否在当前时间之后,验证成立的话被注释的元素一定是一个将来的日期@Pattern
验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定Pattern.Flag 的数组,表示正则表达式的相关选项。
数值检查
建议使用在Stirng,Integer类型,不建议使用在 int 类型上,因为表单值为 空 时无法转换为 int,@Min
验证 Number 和 String 对象是否大等于指定的值@Max
验证 Number 和 String 对象是否小等于指定的值@DecimalMax
被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度( Double, float, BigDecimal )@DecimalMin
被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度@Digits
验证 Number 和 String 的构成是否合法@Digits(integer=,fraction=)
验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。@Range(min=, max=)
被指定的元素必须在合适的范围内@Range(min=10000,max=50000,message=”range.bean.wage”)
@Valid
递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)@CreditCardNumber
信用卡验证@Email
验证是否是邮件地址,如果为null,不进行验证,算通过验证。@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
controller
在 controller 中搭配 @Valid
BindingResult
使用, 校验entity的数据
1 |
|
Spring data jpa
Spring data jpa 在事务提交前也会触发,如果数据没通过校验会出现如下类似的异常
1 | org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction |
这是异常,应该要避免出现。
Bean Validation 还可自定义规划并且手动触发校验。
注意 MoneyValidator
和 Money
相互一致
自定义Validation注解
1 | import xxx.MoneyValidator; |
自定义Validation校验
1 | import xxx.Money; |
手动触发
1 | import javax.validation.ConstraintViolation; |
bean
1 |
|
@Money 给 mobile校验仅仅是玩笑
zookeeper 安装
更新历史
无
计划zookeeper安装路径为 /data/zookeeper
, 以 apache-zookeeper-3.6.3
为例。
1 | tar xvf apache-zookeeper-3.6.3-bin.tar.gz -C /data |
1 | cd /data/zookeeper/conf |
zoo.cfg
内容如下,admin.serverPort
根据实际情况修改, 默认会 占用8081
1 | # The number of milliseconds of each tick |
脚本vim /usr/lib/systemd/system/zookeeper.service
zookeeper.service 内容如下:
1 | [Unit] |
执行以下命令重载unit配置文件
1 | systemctl daemon-reload |
开机启动
1 | systemctl enable zookeeper |
ResouManager(NM):
负责处理客户端请求
监控 NodeManager
启动和监控 APPlicationMaster
资源的分配和调度
NodeManager:
管理单个Worker节点上的资源;
处理来自ResourceManager的命令
处理来自ApplicationMaster的命令
汇报资源状态
ApplicationMaster:
负责数据的切分
为应用申请计算资源,并分配给Task
任务的监控与容错
运行在Worker节点上
Container:
资源抽象,封装了节点上的多维度资源,如CPU,内存,网络资源等。
Dispatcher
整体的设计思路是一个生产者和消费者模型,支持的多生产者和多消费者的模式。
硬件
所有服务器统一 4核CPU 16G内存
软件
CentOS 7.9
OpenJDK 11
hadoop 3.3.1
目录结构
安装目录和数据目录分离,软件都安装在/home/hadoop
,数据都存储在/data/hadoop
,系统安装时建议/data
单独分区。
1 | # hadoop软件安装目录 |
1 | uname -a |
使用阿里云的yum源
所有服务器都需操作
1 | mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup |
所有服务器都需操作
1 | # delete 默认 JDK |
1 | # 切换 java版本 |
所有服务器都需操作
1 | mkdir -p /data/hadoop/zk/data |
按实际情况 所有服务器都需操作vim /etc/profile
1 | # hadoop env ----------- |
立即生效source /etc/profile
所有服务器都需操作
hostname
按规划设置hostname, 重启后生效
1 | hostnamectl set-hostname xxx |
hostname与ip映射
可修改本机/etc/hosts/
或在本地dns服务器上设置
1 | # hadoop |
所有服务器都需操作
1 | useradd hadoop |
所有服务器都需操作
测试环境简单操作关闭防火墙, 正式环境看情况
1 | setenforce 0 |
以下操作都是在hadoop账户进行!!! 以下操作都是在hadoop账户进行!!! 以下操作都是在hadoop账户进行!!! 以下操作都是在hadoop账户进行!!!
1 | ## 1) 生成公私钥 |
1 | ## 1) 生成公私钥 |
1 | scp /home/hadoop/.ssh/authorized_keys hadoop-master-b.chinauh.cn:/home/hadoop/.ssh/ |
按规划,在hadoop-data-1 上 下载 zookeeper ,官网
1 | tar xvf apache-zookeeper-3.7.0-bin.tar.gz |
1 | /data |
1 | $ cd /home/hadoop/apache-zookeeper-3.7.0/conf/ |
1 | scp -r /home/hadoop/apache-zookeeper-3.7.0 hadoop-data-2.chinauh.cn:/home/hadoop/ |
1 | [hadoop@hadoop-data-1 hadoop]$ /home/hadoop/apache-zookeeper-3.7.0/bin/zkServer.sh start |
登录主机hadoop-master-a
, 配置文件主要在 /home/hadoop/hadoop-3.3.1/etc/hadoop
目录里
hadoop-env.sh
1 | export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-11.0.12.0.7-0.el7_9.x86_64/ |
1 |
|
1 |
|
1 |
|
注意 yarn.nodemanager.resource.memory-mb
, yarn.scheduler.minimum-allocation-mb
, yarn.scheduler.maximum-allocation-mb
根据服务器内存调整。
1 | <?xml version="1.0"?> |
在hadoop-master-a节点的workers文件内把localhost删除,加入
1 | hadoop-data-1.chinauh.cn |
将/home/hadoop/hadoop-3.3.1拷贝到集群其他机器上面
1 | $ scp -r /home/hadoop/hadoop-3.3.1 hadoop-master-b.chinauh.cn:/home/hadoop/ |
1 | #在hadoop-master-a 上 格式化 |
类似这样成功
1 | #验证:检查zookeeper上是否已经有Hadoop HA目录,在任意一台zk节点上面 |
启动namenode日志同步服务journalnode,所有ZooKeeper节点均启动,
journal 会监听 8485 端口, namenode -format
会连接此服务
1 | [hadoop@hadoop-data-1 ~]$ $HADOOP_HOME/bin/hdfs --daemon start journalnode |
hadoop-master-a
格式化NAMENODE,并启动namenode1 | [hadoop@hadoop-master-a ~]$ $HADOOP_HOME/bin/hdfs namenode -format |
1 | # 验证 |
1 | [hadoop@hadoop-master-b ~]$ $HADOOP_HOME/bin/hdfs namenode -bootstrapStandby |
1 | [hadoop@hadoop-master-b ~]$ $HADOOP_HOME/bin/hdfs --daemon start namenode |
1 | # 验证 |
在所有namenode节点上,启动DFSZKFailoverController
1 | [hadoop@hadoop-master-a ~]$ $HADOOP_HOME/bin/hdfs --daemon start zkfc |
1 | # 验证 |
1 | [hadoop@hadoop-master-b ~]$ $HADOOP_HOME/bin/hdfs --daemon start zkfc |
1 | # 验证 |
1 | [hadoop@hadoop-master-a ~]$ $HADOOP_HOME/bin/hdfs --workers --daemon start datanode #启动所有的datanode节点 |
1 | # 验证 |
主resourcemanager
1 | [hadoop@hadoop-master-b ~]$ $HADOOP_HOME/bin/yarn --daemon start resourcemanager |
1 | # 验证 |
备resourcemanager
1 | [hadoop@hadoop-master-a ~]$ $HADOOP_HOME/bin/yarn --daemon start resourcemanager |
1 | # 验证 |
nodemanager
1 | # 启动NodeManager |
1 | # 验证 |
1 | #1 datanode 报告 |
领域驱动设计
参考书籍:
领域驱动设计精粹
领域驱动设计与模式实战
MVC
缺点:
+ 底层是基础设施层, 领域层依赖于基础设施层
依赖倒置的原则(DIP)由Robert C. Martin :
高层模块不应该依赖于底层模块,两者都应该依赖于抽象抽象不应该依赖于实现细节,实现细节应该依赖于接口
事实上已经没有分层概念了。无论高层还是底层,实际只依赖于抽象,整个分层好像被推平了。
也是一种分层架构,只不过不是上下或左右,而是变成了内部和外部。
从外环到内环,软件的层级逐渐升高。
外环(low level)依赖内环(high level)。
1 | DDD |
系统内部,具体技术实现;
仓库,文档,缓存,消息机制,领域事件发布/监听;
一般如下类型:
controller
API
层, 程序入口,客户端调用;一般如下类型:
应用服务,传统 service
层, 一般跟场景(用例)有关。
一般如下类型:
一个场景(用例),对应一个command,对应一个handler
一般如下类型:
一般如下类型:
当领域遜辑放某-一个聚合里不合适,需要协调多个聚合,但由于是领域逻辑,放在应用服务里不合适的时候,可以放到领域服务里;
需要访问数据库等外部资源的业务逻辑,不建议聚合里,可以放到领域服务里
有些算法、策略代码,为了保持实体和值对象的职责单- - ,可以提炼出来变成领域服务( 领域服务类的命名不-定都要以Service结尾)
不涉及事务处理
分开对待本质复杂度和偶然复杂度,核心业务逻辑被封装在领域对象里,内聚,容易保持一致性, 且容易维护和扩展。
此外,容易测试,且代码和测试都可以作为文档。
对象引用多, 内存占用大, 影响吞吐量
聚合是一组相关领域模型的集合,是用来封装业务的不变性。同时强迫大家尽可能的简化领域模型之间的关联关系。在贫富之间寻找平衡。
聚合的主要原则包括:
聚合是-致性边界,聚合根负责执行业务规则,改变边界内的任一对象的状态都不能违反整个聚合的所有业务规则;
聚合根有全局标识,聚合边界内的其他实体只有局部标识,聚合边界外的对象,只能持有聚合根的标识
,不能引用聚合根对象
,也不能持有聚合内部对象或标识
聚合具有整体的生命周期,删除聚合根,聚合内的所有对象都需要删除
只有聚合根能从持久化系统内查询得到,边界内的对象只能从聚合根导航访问
应用服务作为事务一致性边界,一个事务里不能涉及到两个聚合的修改,跨聚合的数据应该使用最终一致。
但最终一致性成本很高。
实例代码中,基于内存实现同步的领域事件发布和订阅。这样,实际上两个聚合根的更改基于同一个本地数据库事务。
但由于使用了事件驱动,在代码层面,两个聚合根的更新是解耦的,在需要最终一致性的时候容易重构。
]]>1 | spark-submit --class.org.apache.spark.examples.SparkPi \ |
run-example SparkPi
内存不足,在cm里配置yarn
1 | yarn.scheduler.maximum-allocation-mb |
dfs
如果直接 root 执行,会有如下错误
1 | ╰─# spark-shell |
查看
1 | ╰─# hadoop fs -ls / 1 ↵ |
解决方案
You need to have a user home directory on HDFS. Log as the HDFS user and create a home dir for root.
其他用户类似。
hadoop的用户是hdfs, 默认是不能直接登录的
1 | sudo -u hdfs hadoop fs -mkdir /user/root |
1 | ╰─# hadoop fs -ls /user |
然后root用户可以执行 spark-shell
其实直接用 spark 用户执行就可以。
1 | ╰─# sudo -u spark spark-shell |
弹性分布式数据集(Resilient Distribution Dataset)
数据集合
Pair RDD键值对操作
https://blog.csdn.net/u014646662/article/details/84673920
https://blog.csdn.net/JasonDing1354/article/details/46845585
CDH Cloudera’s Distribution, including Apache Hadoop。 Cloudera 公司出品。
拥有集群自动化安装、中心化管理、集群监控、报警功能的一个工具(软件),使得集群的安装可以从几天的时间缩短为几个小时,运维人数也会从数十人降低到几个人,极大的提高了集群管理的效率。
使用NTP服务 同步时间相关服务器时间
ntpd, ntpdate
1 | echo "*/20 * * * * /usr/sbin/ntpdate pool.ntp.org" | sudo tee -a /etc/crontab > /dev/null |
根据不同机器角色设置 hostname, 如下 master
1 | hostnamectl set-hostname master |
master slave 都配置好,要和 hostname 匹配, 如下例子:
vim /etc/hosts
1 | 192.168.8.23 master-23 |
公钥要分发到所有slave机器
1 | ssh-keygen -t rsa -C "your_email@your_email.com" -b 4096 |
使用当前最新版本 6.3.1
, 只需要在master上安装。网络原因,可使用 清华的代理 https://cloudera.proxy.ustclug.org/cm6/6.3.1/redhat7/yum/RPMS/x86_64/
。
下载如下的包
1 | cloudera-manager-agent-6.3.1-1466458.el7.x86_64.rpm |
安装
到下载目录
1 | yum install -y ./*.rpm |
1 | $ wget https://cloudera.proxy.ustclug.org/cm6/6.3.1/cloudera-manager-installer.bin |
cdh/opt/cloudera/
jdk/usr/java/
cloudera/var/lib/cloudera-scm-*
cm 安装成功后,重启系统, 大约 1min,
服务为 cloudera-scm-agent.service
和 cloudera-scm-server.service
localhost:7180 可访问, 初始账户 admin, 密码 admin
slave 都安装好 jdk,cm daemons, cm agent,
可以避免 下载速度慢
将 master上的
cloudera-manager-agent-6.3.1-1466458.el7.x86_64.rpm
cloudera-manager-daemons-6.3.1-1466458.el7.x86_64.rpm
oracle-j2sdk1.8-1.8.0+update181-1.x86_64.rpm
copy 到 slave上,像master 一样安装。
1 | yum install -y cloudera-manager-daemons-6.3.1-1466458.el7.x86_64.rpm cloudera-manager-agent-6.3.1-1466458.el7.x86_64.rpm oracle-j2sdk1.8-1.8.0+update181-1.x86_64.rpm |
注意:
cloudera-scm 必须拥有 /opt/cloudera 路径的所有权。
1 | chown -R cloudera-scm:cloudera-scm /opt/cloudera |
安装完成重启系统。
parcels(离线) 方式, 注意一定要检测到 所需的cdh
仅需要在master安装
默认是内存数据库,如果上生产,建议还是关系数据库。
官方文档
可去清华镜像下载
1 | wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.46.tar.gz |
1 | /opt/cloudera/cm/schema/scm_prepare_database.sh -h 192.168.11.229 mysql --scm-host 192.168.11.220 -u root -P 3306 -p scm scm |
如果 是本机数据库, -h 和 –扫描-host 去掉
依次输入 root 和 scm 密码
如果存在,删除embedded PostgreSQL properties
1 | rm /etc/cloudera-scm-server/db.mgmt.properties |
官网
https://cloudera.proxy.ustclug.org/cdh6
国内镜像
https://cloudera.proxy.ustclug.org/cdh6/6.3.2/parcels/
对应操作系统下载文件
manifest.jsonCDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcelCDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel.sha1CDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel.sha256
仅需上传到 master的目录/opt/cloudera/parcel-repo
下, CDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel.sha1
copy 一份成为 CDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel.sha1
注意:
cloudera-scm 必须拥有 /opt/cloudera 路径的所有权,否则 cloudera manage 会无法识别 CDH。
一旦出现,如下操作。 如再不能识别,重启master操作系统。
1 | chown -R cloudera-scm:cloudera-scm /opt/cloudera |
如果仍然无法识别,
cloudera express
需要解决详细报告内的问题。
swappiness
1 | vim /etc/sysctl.conf |
透明大页面压缩
1 | echo never > /sys/kernel/mm/transparent_hugepage/defrag |
如果 slave 安装异常,
解决方法:
systemctl restart cloudera-scm-agent
1 | Configurator not found |
1 | public <R> Observable<R> compose(Transformer<? super T, ? extends R> transformer) { |
常用的泛型含义:
caching_sha2_password
, mysql_native_password
, 做如下配置my.cnf
1 | [mysqld] |
修改密码
1 | mysql> |
Let’s Encrypt是一个于2015年三季度推出的数字证书认证机构,旨在以自动化流程消除手动创建和安装证书的复杂流程,并推广使万维网服务器的加密连接无所不在,为安全网站提供免费的SSL/TLS证书。
本文以 Cent OS 7
版本为例说明, 使用 certbot
提供Let’s Encrypt服务 。
更新历史
无
certbot
选择对应web 服务和 操作系统
按照说明 一步一步 操作就行.
1 | yum -y install python-urllib3 |
1 | certbot |
可以修改域名证书
]]>分布式批处理框架, 采用 spring boot
2, quartz
2 集群
本文以 spring boot
V2.2.5 版本为例说明。
更新历史
无
POM文件大体如下:
1 | <parent> |
1 | spring: |
job
1 | package com.mandalat.ehealth.job; |
job config
1 | package com.mandalat.ehealth.common.config; |
分别在 8080 和 8081 上 启动服务;
可以看到只有一台服务调用到了 AJob
中的方法;
把这台服务关闭, 5秒后可以看到另一台服务调用到了 AJob
中的方法;
说明Quartz 的集群分布式部署成功.
idea
更新历史
2019-09-23 增加 idea 远程 debug
eclipse 和 idea 常用快捷键 对比 (转载)
Eclipse | IntelliJ IDEA | Description |
---|---|---|
F4 | ctrl+h | show the type hierarchy |
ctrl+alt+g | ctrl+alt+F7 | find usages |
ctrl+shift+u | ctrl+f7 | finds the usages in the same file |
alt+shift+r | shift+F6 | rename |
ctrl+shift+r | ctrl+shift+N | find file / open resource |
ctrl+shift+x, j | ctrl+shift+F10 | run (java program) |
ctrl+shift+o | ctrl+alt+o | organize imports |
ctrl+o | ctrl+F12 | show current file structure / outline |
ctrl+shift+m | ctrl+alt+V | create local variable refactoring |
syso ctrl+space | sout ctrl+j | System.out.println(“”) |
alt + up/down | ctrl + shift + up/down | move lines |
ctrl + d | ctrl + y | delete current line |
??? | alt + h | show subversion history |
ctrl + h | ctrl + shift + f | search (find in path) |
“semi” set in window-> preferences | ctrl + shift + enter | if I want to add the semi-colon at the end of a statement |
ctrl + 1 or ctrl + shift + l | ctrl + alt + v | introduce local variable |
alt + shift + s | alt + insert | generate getters / setters |
ctrl + shift + f | ctrl + alt + l | format code |
ctrl + y | ctrl + shift + z | redo |
ctrl + shift + c | ctrl + / | comment out lines |
ctrl + alt + h | ctrl + alt + h (same!) | show call hierarchy |
none ? | ctrl + alt + f7 | to jump to one of the callers of a method |
ctrl + shift + i | alt + f8 | evaluate expression (in debugger) |
F3 | ctrl + b | go to declaration (e.g. go to method) |
ctrl + l | ctrl + g | go to line |
alt + / | ctrl + space | eclipse:Content Assist ; idea:completion 跟输入法冲突,自己改 |
??? | ctrl + shift + a | 查找所有Intellij的命令 |
??? | ctrl + shift + alt + t | 重构所有 |
Shortcut Translator插件, 安装后,按Ctrl+Shift+K调出快捷键翻译对话框,选定你惯用的IDE keymap和需要学习的keymap,按下惯用keymap的快捷键,即可看到学习keymap上的对应快捷键。
新建好server, before launch : Maven Goal -》 clean package
Live templates
增加 java method comment
jmc : /**
File and Code templates
Includs 可以修改成如下内容:
/*** Created with ${PRODUCT_NAME}.* User: ${USER}* Date: ${DATE}* Time: ${TIME}* description: */
编辑 .properties 文件
settting –》 File Encodings –》 Transparent native-to-ascii conversion 打勾
限制一行代码的宽度
File->settings->Code Style->General中,修改“Right margin (columns)”的值即可改变代码行宽度的限制。
自动将代码换行:
第一种,在上述的“Right margin (columns)”的下方,有“Wrap when typing reaches right margin”选项,选中它,是什么效果呢?如下图所示,随着输入的字符的增加,当代码宽度到达界线时,IDEA会自动将代码换行。
第二种,在File->settings->Code Style->Java中,选中“Wrapping and Braces”选项卡,在“Keep when reformatting”中有一个“Ensure rigth margin is not exceeded”,选中
quick doc
eclipse 光标放类或方法上, 默认有javaDoc 等 doc 显示;
idea 默认没有, 可以用 CTRL + Q
手动显示,或者 setting -> editor -> general
页面, other 部分, 将 show quick documentation
打上勾
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8006
SpringBoot
1 | jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8006 -jar test-center.jar |
Tomcat
修改启动脚本
1 | JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8006" |
spring boot 构建war包
本文以 spring boot
V2.1.0 版本为例说明。
更新历史
无
spring boot
默认是 可执行的 JAR 包,如果需要构建 war包, 仅需修改如下2个文件
POM.xml
在原有基础下 增加
1 | <dependency> |
Application.java
继承 SpringBootServletInitializer
, 实现方法 configure(SpringApplicationBuilder application)
类似如下:
1 |
|
JVM调优的工具和方法 深入浅出,分如下3节介绍,可以解决实际问题。
本章解决java线上CPU调优
工具介绍
公欲善其事,必先利其器
jps, jstat, jmap, jhat, jstack, jinfo, JConsole, VisualVM, Eclipse Memory Analyzer(MAT)
CPU调优
还我CPU
Memory调优
吃我的吐出来
更新历史
TOP命令查看到CPU的占用情况
TOP –> P : 按CPU使用率排序
具体线程
Java是一个多线程应用,进程是由多个线程构成的,上面看到的是这个进程的CPU占用率,导致这个进程CPU偏高的是其中某个或某几个线程,因而我们需要找到这些线程。
ps命令查看指定进程的线程情况
1 | ps -mp <pid> -o THREAD,tid,time |
线程tid为 9100 的线程,CPU占用率达到了99.8%, 就是这个线程的问题。
请出 jstack
分析具体线程。
** 注意: 进制转换 **
ps命令查看到的线程ID 9100 是十进制,jstack
命令输出的线程ID可能是十六进制,使用如下命令转换
1 | ╰─$ printf "%x\n" 9100 |
然后使用 jstack
定位具体的问题
1 | ╰─$ jstack 9078|grep 238c -A 15 |
最后结合源码检查就ok。
]]>JVM调优的工具和方法 深入浅出,分如下3节介绍,可以解决实际问题。
本章讨论java线上内存调优
工具介绍
公欲善其事,必先利其器
jps, jstat, jmap, jhat, jstack, jinfo, JConsole, VisualVM, Eclipse Memory Analyzer(MAT)
CPU调优
还我CPU
Memory调优
吃我的吐出来
更新历史
Java应用占用太多内存也有可能的确是内存硬件不足或JVM设置的太小,记得最后考虑下。
本文主要讨论的是Java内存泄漏。
出现如下情况之一,就需要检查了
File/Text buffers 等资源没关闭
静态集合类引用
静态变量的生命周期和应用程序一致,他们所引用的所有的对象也不能被释放。
监听器
只增加监听器,不删除
各种连接没有释放
单例模式
单例对象在被初始化后将在JVM的整个生命周期中存在,单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收
内部类和外部模块等的引用
非静态内部类的对象会隐式强引用其外围对象,所以在内部类未释放时,外围对象也不会被释放,从而造成内存泄漏。
集合中的可变对象修改
一般是HashSet, HashMap, 主键的key的hashCode变化以后,添加或者删除都是映射到不同的桶中。所以对于HashSet或者HashMap的Key,都应该是不可变类型。
1 | class Person{ |
java启动加入-XX:+HeapDumpOnOutOfMemoryError
,发生OOM时自动生成dump文件
java … -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./oom.hprof
发生OOM异常时需要对该文件进行分析。把oom.hprof 下载到开发环境,使用 MAT
分析。
jps
找到java进程ID[pid]
top -p [pid] 查看内存使用情况
1 | ╰─$ top -p 14986 |
FullGC情况jstat -gcutil [pid] 3s
每3s的GC情况,主要看 FGC
1 | ╰─$ jstat -gcutil 14986 3s |
jmap
查看目前的各种类型的对象创建数目和所占用内存
1 | ╰─$ jmap -histo:live 14986|more |
还可以生成JVM的内存dump文件,下载到本地使用 MAT
分析
jmap -dump:format=b,file=文件名 [pid]
JVM调优的工具和方法 深入浅出,分如下3节介绍,可以解决实际问题。
本章首先介绍各种倚天剑和屠龙刀
(致敬 金庸大大)
工具介绍
公欲善其事,必先利其器
jps, jstat, jmap, jhat, jstack, jinfo, JConsole, VisualVM, Eclipse Memory Analyzer(MAT)
CPU调优
还我CPU
Memory调优
吃我的吐出来
更新历史
TIPs: 以下命令都尽量在启动JVM的用户环境下使用
JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
jps [-q] [-mlvV] [<hostid>]
参数都非必须
-q : 只输出LVMID-l : 输出主类全名或jar路径-m : 输出JVM启动时传递给main()的参数-v : 输出JVM启动时显示指定的JVM参数
╰─$ jps -l 15346 org.jetbrains.idea.maven.server.RemoteMavenServer15527 org.jetbrains.jps.cmdline.Launcher14986 com.intellij.idea.Main30074 jdk.jcmd/sun.tools.jps.Jps18941 org.jetbrains.jps.cmdline.Launcher
jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,类装载、内存、垃圾收集、JIT编译等数据
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
[option] : 操作参数vmid : 本地虚拟机进程ID[interval] : 连续输出的时间间隔[count] : 连续输出的次数
Option | 解释 |
---|---|
gc | 垃圾回收堆的行为统计。Statistics of the behavior of the garbage collected heap. |
class | class loader的行为统计。Statistics on the behavior of the class loader. |
compiler | HotSpt JIT编译器行为统计。Statistics of the behavior of the HotSpot Just-in-Time compiler. |
gccapacity | 各个垃圾回收代容量(young,old,perm)和他们相应的空间统计。Statistics of the capacities of the generations and their corresponding spaces. |
gcutil | 垃圾回收统计概述。Summary of garbage collection statistics. |
gccause | 垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因。Summary of garbage collection statistics (same as -gcutil), with the cause of the last and |
gcnew | 新生代行为统计。Statistics of the behavior of the new generation. |
gcnewcapacity | 新生代与其相应的内存空间的统计。Statistics of the sizes of the new generations and its corresponding spaces. |
gcold | 年老代和永生代行为统计。Statistics of the behavior of the old and permanent generations. |
gcoldcapacity | 年老代行为统计。Statistics of the sizes of the old generation. |
gcpermcapacity | 永生代行为统计。Statistics of the sizes of the permanent generation. |
printcompilation | HotSpot编译方法统计。HotSpot compilation method statistics. |
-gc
常用命令 垃圾回收堆的行为统计
╰─# jstat -gc 15490 3sS0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 8192.0 33792.0 8181.8 0.0 724992.0 592657.6 215040.0 81474.7 90880.0 86753.7 11520.0 10764.0 20 0.625 3 0.365 0.9908192.0 33792.0 8181.8 0.0 724992.0 594107.5 215040.0 81474.7 90880.0 86753.7 11520.0 10764.0 20 0.625 3 0.365 0.9908192.0 33792.0 8181.8 0.0 724992.0 594455.2 215040.0 81474.7 90880.0 86753.7 11520.0 10764.0 20 0.625 3 0.365 0.9908192.0 33792.0 8181.8 0.0 724992.0 595905.2 215040.0 81474.7 90880.0 86753.7 11520.0 10764.0 20 0.625 3 0.365 0.990
C即Capacity 总容量,U即Used 已使用的容量
更多可参考jstat java高分局之jstat命令使用
jinfo(JVM Configuration info)实时查看和调整虚拟机运行参数
jinfo <option> <pid>
-flag : 输出指定args参数的值-flags : 不需要args参数,输出所有JVM参数的值-sysprops : 输出系统属性,等同于System.getProperties()
jmap(JVM Memory Map)命令用于生成heap dump文件,如果不使用这个命令,还可以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候自动生成dump文件。
又或者在Linux系统下通过Kill-3命令发送进程退出信号“吓唬”一下虚拟机,也能拿到dump文件。
jmap不仅能生成dump文件,还可以查询finalize执行队列、Java堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。
openjdk 需要 安装 debuginfo
,版本需要和openjdk 一致
1 | yum update java-1.8.0-openjdk.x86_64 |
否则 异常
1 | - unknown CollectedHeap type : class sun.jvm.hotspot.gc_interface.CollectedHeap |
jmap [option] pid
dump : 生成堆转储快照finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象heap : 显示Java堆详细信息histo : 显示堆中对象的统计信息clstats : 类加载的统计信息F : 当-dump没有响应时,强制生成dump快照
dump.hprof这个后缀是为了后续可以直接用MAT(Memory Anlysis Tool)打开。
-finalizerinfo
打印等待回收对象的信息
-heap
打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况,可以用此来判断内存目前的使用情况以及垃圾回收情况
1 | ╰─# jmap -heap 15490 |
-histo
打印堆的对象统计,包括对象数、内存大小等等 (因为在dump:live前会进行full gc,如果带上live则只统计活对象,因此不加live的堆大小要大于加live堆的大小 )
1 | $ jmap -histo:live 15490 | more |
xml class name是对象类型,说明如下:
B byte C char D double F float I int J long Z boolean [ 数组,如[I表示int[] [L+类名 其他对象
-clstats
打印Java堆内存的类加载器的统计信息。对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印。
1 | jmap -clstats 15490 |
jhat(JVM Heap Analysis Tool)命令是与jmap搭配使用,用来分析jmap生成的dump。
千万下载dump文件到开发环境进行分析。
推荐使用 Eclipse Memory Analyzer(MAT)
jstack(Stack Trace for Java)用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)。
线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源等。
如果现在运行的java程序呈现停顿状态,jstack是非常有用的。
jstack [-l][-e] <pid>
-l long listing. Prints additional information about locks-e extended listing. Prints additional information about threads
参考 jstack
以下都是可视化的工具
JConsole(Java Monitoring and Management Console)是一种基于JMX的可视化监视、 管理工具
大名鼎鼎的 VisualVM, 基于NetBeans平台开发,通过插件扩展支持,VisualVM可以做到
Eclipse 出品,MAT可以对堆dump的文件进行分析,可以去detail页看线程各个对象的使用数目等情况。
swagger
(springfox
) 可帮助开发人员设计,构建,记录和使用RESTful Web服务, 使后台开发人员与移动端开发人员更好的对接.
大多数用户通过Swagger UI工具可很简单识别和使用Swagger。
最大优点: 接口开发人员不用另外写接口文档,代码注释中写上swagger相关的注释就可以自动生成接口文档;
最大缺点: 对源代码侵入比较严重。
本文以 springfox-swagger2
V2.9.2 版本为例说明。
末了,还有个稍重量级竞品 RAP(阿里妈妈出品) , 感兴趣的可以去玩玩。
更新历史
+2018-11-04: 增加swagger注解具体说明
1 | <dependency> |
1 |
|
Springboot 可以直接使用
java based config
1 |
|
xml based config
1 | <!--<bean class="com.springfox.config.SwaggerConfig" /> 使用bean申明可以去掉@configuration--> |
controller
1 |
|
entity
1 | /** |
@Api:标志这个类为Swagger资源,根据config, 没标注的不会生成 swagger 的接口文档
@ApiImplicitParams,@ApiImplicitParam: 对参数进行说明, 其中dataType一定为小写; allowableValues 可限制 合法值得列表; required 指定该参数是否必须
@ApiOperation:描述了一种操作或通常针对特定的路径的HTTP方法。 response 指定返回值类型;authorizations 指定改接口的认证条件, apiKey 需要和 config的一致;
@ApiModel: 描述一个实体
@ApiModelProperty:描述一个字段
ComResultVo<UserEntity>
这种带泛型的返回值,想要正常完全显示,需要注意如下:
ComResultVo
内需要正确的 get/set
方法ComResultVo<UserEntity>
一定要 标明泛型的具体值 UserEntity
达到如下效果
Authorize
按钮, 填入合法的认证值,模拟授权。
打开 http://localhost:8080/project_name/swagger-ui.html ,project_name表示你启动项目的名称,如果你以根目录启动则没有project_name,当你看到如下界面就表示配置成功了
点开具体接口, 有惊喜 哈哈。Try it out!
可以实时测试接口
]]>