前提

  1. 域名被cloudflare管理
  2. docker环境

使用docker申请

  1. Cloud Flare上去获取Global API Key;并写入到cloudflare.ini配置文件中去

    1
    2
    3
    4
    mkdir certbot

    echo "dns_cloudflare_email = your.email@xxx.com
    dns_cloudflare_api_key = cf-global-token" > certbot/cloudflare.ini
  2. 申请证书

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    docker run -it --rm --name certbot \
    -v ./certbot/etc:/etc/letsencrypt \
    -v ./certbot/lib:/var/lib/letsencrypt \
    -v ./certbot:/.secrets \
    certbot/dns-cloudflare certonly \
    --non-interactive \
    --dns-cloudflare \
    --dns-cloudflare-credentials /.secrets/cloudflare.ini \
    --dns-cloudflare-propagation-seconds 60 \
    -m your.email@xxx.com \
    --agree-tos \
    --no-eff-email \
    -d '*.your.domain'
  3. renew证书

    1
    2
    3
    4
    5
    docker run -it --rm --name certbot \
    -v "./certbot/etc:/etc/letsencrypt" \
    -v "./certbot/cloudflare.ini:/cloudflare.ini" \
    certbot/dns-cloudflare renew \
    --dns-cloudflare --dns-cloudflare-credentials /cloudflare.ini

Java线上问题排查经验集合

high cpu

  1. 使用Top -H 查看CPU占用较高的线程ID。如:
    top-H
    1
    2
    3
    4
    5
    6
    7
    jps -l # find the right process ,if pid is 1
    top -H -p 1 # find the top thread CPU usage in this process. different linux commond may different.
    jstack 1 > stack.log # get current java thread info ,save to stack.log file
    #if the CPU usage top 1 is 7
    printf %x 7 # get the 16 hexadecimal value of thread id
    #find the thread info from stack.log, can use vim or other commond to find.
    grep "0x7" -A 10 stack.log
  2. 获得了thread info后,当然这里也可以通过其他方式获取线程栈信息,比如 show-busy-java-threadsarthas thread,可以分析堆栈信息,比如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    "http-nio-8080-exec-2" #20 daemon prio=5 os_prio=0 cpu=0.90ms elapsed=155.86s tid=0x00001465ecfb8800 nid=0x2b waiting on condition  [0x00001465ac2c4000]
    java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(java.base@11.0.18/Native Method)
    at com.dockerforjavadevelopers.hello.HelloController.index(HelloController.java:12)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.18/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.18/NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.18/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@11.0.18/Method.java:566)
    ....
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    - locked <0x000000062aa88668> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(java.base@11.0.18/Thread.java:829)
    线程停留在了,java.lang.Thread.sleep(java.base@11.0.18/Native Method) 我们需要在线程栈中找到自己业务的信息,这个示例为
    com.dockerforjavadevelopers.hello.HelloController.index(HelloController.java:12),同时通过这个信息我们知道当前线程状态为:TIMED_WAITING,其实并不会消耗cpu(为示例使用的Thread.sleep, 通常这一步会找到占用cpu时间超长的thread)
    阅读全文 »

PlatformTransactionManager&TransactionAwareCacheDecorator 源码解析+问题排查

1.问题现象

在原有使用中发现原有删除缓存的操作未能正常执行。原code 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
@Transactional
void function{
db_action();
db_action2();
//在上方事务提交后,进行缓存和通知其他service动作
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
deleteCache();
action2();
}
})
}

排查思路:
1.确认afterCommit 是否被调用
发现被调用,但是查看缓存后没有被执行
2. 了解afterCommit如何被处理
3. 尝试debug transactionManager 执行部分Code,确定整体流程

阅读全文 »

Git设置代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
设置:
git config --global https.proxy http://127.0.0.1:1080
git config --global https.proxy https://127.0.0.1:1080
或者:
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

取消:
git config --global --unset http.proxy

git config --global --unset https.proxy

特殊设置:

git config --global http.https://github.com.proxy socks5://127.0.0.1:1080

git config --global --unset http.https://github.com.proxy

Idea设置代理

1
2
File->Settings->Appearance&Behavior->System Settings->HTTP Proxy
socks;localhost;1080

Oracle insert into慢,优化方案选择和测试

Oracle端

  • 默认插入耗时
  • Nologing插入耗时
  • APPEND 不寻址,不去寻找 freelist 中的free block , 直接在table HWM 上面加入数据
  • parallel 并行
  • 临时表+批量插入耗时

    创建测试环境

  1. 表结构:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    -- Create table
    create table LOG_OPERATING
    (
    id VARCHAR2(20) not null,
    type CHAR(1) not null,
    operator VARCHAR2(50) not null,
    operator_id VARCHAR2(50) not null,
    url VARCHAR2(255),
    ip VARCHAR2(65) not null,
    model VARCHAR2(40) not null,
    description VARCHAR2(255) not null,
    time DATE not null,
    is_successful CHAR(1) default 1
    )
    tablespace USERS
    pctfree 10
    initrans 1
    maxtrans 255
    storage
    (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
    );
    -- Create/Recreate primary, unique and foreign key constraints
    alter table LOG_OPERATING
    add constraint PK_LOG_OPERATING primary key (ID)
    using index
    tablespace USERS
    pctfree 10
    initrans 2
    maxtrans 255
    storage
    (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
    );
  2. Oracle版本
    1
    2
    3
    4
    5
    6
    7
    8
    SQL>select * from v$version;
    BANNER
    ---------------------------------------------------------------------
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    PL/SQL Release 11.2.0.1.0 - Production
    CORE 11.2.0.1.0 Production
    TNS for Linux: Version 11.2.0.1.0 - Production
    NLSRTL Version 11.2.0.1.0 - Production

    Insert测试

  3. 默认操作,无任何优化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    declare i int:=1;
    begin
    while i<=1000000 loop
    insert into log_operating
    (id,
    type,
    operator,
    operator_id,
    url,
    ip,
    model,
    description,
    time,
    is_successful)
    values
    (i,
    '1',
    'pki_user',
    '399262438320640000',
    '/v1/common/dict/certApplyType',
    '192.168.1.1',
    '通用方法',
    '获取该类型下的值',
    SYSDATE,
    '1');
    i:=i+1;
    end loop;
    end
    commit;
    耗时:77.298秒

2.添加Nologing

1
2
3
alter table log_operating nologging; 
--insert
alter table log_operating logging;

耗时:68.259秒

3.添加 /*+ append */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
declare i int:=1;
begin
while i<=1000000 loop
insert /*+ append */ into log_operating
(id,
type,
operator,
operator_id,
url,
ip,
model,
description,
time,
is_successful)
values
(i,
'1',
'pki_user',
'399262438320640000',
'/v1/common/dict/certApplyType',
'192.168.1.1',
'通用方法',
'获取该类型下的值',
SYSDATE,
'1');
i:=i+1;
end loop;
end
commit;

耗时:67.258秒

3.NOloging+/*+ append */

1
2
alter table log_operating nologging;
--插入

耗时:68.85秒

4.临时表+NOloging+/*+ append */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
alter table log_operating nologging;


declare i int:=1;
begin
while i<=1000000 loop
insert into TEMP_LOG_OPERATING
(id,
type,
operator,
operator_id,
url,
ip,
model,
description,
time,
is_successful)
values
(i,
'1',
'pki_user',
'399262438320640000',
'/v1/common/dict/certApplyType',
'192.168.1.1',
'通用方法',
'获取该类型下的值',
SYSDATE,
'1');
i:=i+1;
end loop;
insert /*+ append */ into LOG_OPERATING select * from TEMP_LOG_OPERATING;
truncate table TEMP_LOG_OPERATING;
end
commit;

耗时:54.377秒

5.临时表+NOloging+/*+ append */+parallel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
alter table TEMP_LOG_OPERATING nologging;
alter table LOG_OPERATING nologging;

declare i int:=1;
begin
while i<=1000000 loop
insert into TEMP_LOG_OPERATING
(id,
type,
operator,
operator_id,
url,
ip,
model,
description,
time,
is_successful)
values
(i,
'1',
'pki_user',
'399262438320640000',
'/v1/common/dict/certApplyType',
'192.168.1.1',
'通用方法',
'获取该类型下的值',
SYSDATE,
'1');
i:=i+1;
end loop;
insert /*+ append parallel(a, 4) nologging */ into LOG_OPERATING select /*+ parallel(b, 4) */ * from TEMP_LOG_OPERATING;
end
commit;
truncate table TEMP_LOG_OPERATING;

耗时:42.173

结论

以上结果可能存在误差,建议使用批量插入+临时表+APPEND+PARELLEL

参考文章:
https://blog.csdn.net/S630730701/article/details/71732405
https://blog.csdn.net/tmaczt/article/details/84134173

基础操作

maven的生命周期操作:
maven clean package install 等,后续可能会补充一下

稍微复杂操作

-DskipTests,不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。

-Dmaven.test.skip=true 不执行测试用例,也不编译测试用例类。

mvn -pl moduleA -am install 多模块项目时,打包指定一个moduleA,会自动打包这个模块所依赖的模块

MySQL 8版本中代码生成时出现无法生成或错误对象信息的问题解决

Flowable代码生成时出现无法创建表,报错表不存在

情况说明:

  1. 数据库中有多个库,并且另一个库中已经有了flowable或activiti相关的表
  2. 配置中已经添加了自动生成表的配置database-schema-update: true

    现象:

    无法创建表,一直报表不存在
    1
    Caused by: java.sql.SQLSyntaxErrorException: Table 'workflow.act_ge_property' doesn't exist

    解决方法:

  3. 在数据库链接后添加配置:nullCatalogMeansCurrent = true
  4. 添加SpringBoot配置-根据自己使用的数据库池:
    1
    spring.datasource.hikari.data-source-properties.nullCatalogMeansCurrent=true
  5. Java代码配置-根据自己使用的数据库池:
    1
    2
    3
    HikariConfig config = new HikariConfig();
    ...
    config.addDataSourceProperty("nullCatalogMeansCurrent", true);

    导致的原因分析

    在MySQL官方更新日志中发现配置修改nullCatalogMeansCurrent从默认为True改成了默认为False,如果你使用DatabaseMetaData.getTables获取所有的表信息,8.0版本驱动将返回所有库的表。
    MySQL Changes in Connection Properties

在Java中如何实现调用命令行

首先申明,不推荐使用此方式,我了解到的情况如下:执行过程是首先克隆一条和当前虚拟机拥有一样环境变量的进程,再用这个新的进程执行外部命令,最后退出这个进程。因此,频繁的创建对CPU和内存的消耗很大
基础代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* run command with one command
*
* @param command command
* @return command out
*/
public static String run(String command) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("bash", "-c", command);
String out = "";
try {
log.info(String.join(" ", processBuilder.command()));
Process process = processBuilder.start();
out = IOUtils.toString(process.getInputStream());
} catch (IOException e) {
log.error("run command error {}", e.getMessage());
e.printStackTrace();
}
return out;
}

需要考虑的问题

  1. 异常数据的输出,是否监控,以及如何监控,之前的做法是新启动一个线程去监听
  2. 使用此方法时,性能会有较大的损耗,如何改善,考虑去除所有监控进行性能对比
  3. 在执行命令出现异常时的异常处理如何。
    以上几点我会在后续的编码中考虑解决,可以关注我的github的demo项目 Git地址

注意事项

  1. 命令无权限
    考虑文件的可执行权限
  2. 等待shell返回
    在process.waitFor()前读取缓冲区
  3. 命令不存在
    需要将你的程序在bin下添加软链接
    以上参考了https://yq.aliyun.com/articles/2362 感谢

SpringCloud Zuul网关在Filter中添加或修改Request参数

使用目的

在网关中经常会处理一些Token或者鉴权信息,在处理完后,将Token处理后,把用户信息放到Request中,方便后续系统的时候。我这次使用的场景有些特别,由于项目需要兼容用户使用RequestBody 传递JSON参数,但是由于当前系统没有对RequestBody做兼容,导致数据获取不到,因此在Zuul中把参数处理完成后传递给后面的应用。

使用环境

1
2
3
4
5
6
7
8
   <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
</parent>

<spring-cloud.version>Dalston.SR2</spring-cloud.version>
阅读全文 »
0%