LOADING

加载过慢请开启缓存 浏览器默认开启

IceOfSummerの博客

还是自己搭的博客靠谱

后面一辈子的博客都在这了!

Arthas诊断线上问题

0. Links

1. 安装arthas

如果没有用docker,直接从官网下载然后丢服务器就行了,如果用的是docker那么就麻烦一点,这里我整了一个脚本来一键安装/启动:

#!/bin/bash
workdir="/opt/arthas-dev"
user=user
container=$1
if [ -z $container ];then
    echo -e "\e[32m用法: arthas-launcher.sh [容器名|容器ID] [用户名(可选,必须和启动应用的用户一致)]\e[0m"
    exit 0
fi
if [ ! -z $2 ];then
    user=$2
fi

function installArthas() {
    echo "开始安装arthas..."
    docker exec -u $user $container mkdir $workdir/arthas
    docker cp jdk-8u381-linux-x64.tar.gz $container:$workdir/jdk.tar.gz
    docker cp arthas-packaging-3.7.1-bin.zip $container:$workdir/arthas/arthas.zip
    docker exec -u root $container chmod 777 $workdir/jdk.tar.gz
    docker exec -u root $container chmod 777 $workdir/arthas/arthas.zip
    docker exec -u $user $container tar zxvf $workdir/jdk.tar.gz -C $workdir
    docker exec -u $user $container unzip $workdir/arthas/arthas.zip -d $workdir/arthas
    docker exec -u $user $container touch $workdir/installedMark
    echo "安装成功!"
}
# --------------main--------------
docker exec -u $user $container test -d $workdir
if [ ! $? -eq 0 ];then
    docker exec -u root $container mkdir $workdir
    docker exec -u root $container chown $user $workdir
    installArthas
fi

docker exec -u $user $container test -e $workdir/installedMark
if [ $? -eq 0 ];then
    docker exec -it -u $user $container $workdir/jdk1.8.0_381/bin/java -jar $workdir/arthas/arthas-boot.jar
else 
    echo "文件完整性校验失败! 重新尝试安装arthas."
    installArthas
fi

2. watch

2.1 基本使用

例如有一个Encoder的encrypt方法我们想要观察,但是由于每次请求这个方法都会被调用很多次,如果不加限制,每次会爆出很多不相干的信息。

watch提供了一个condition-express选项来帮助我们过滤输出:

watch xxx.Encoder encrypt {returnObj} 'params[0]=="P@ssw0rd"'

上面这条指令则是让arthas在第一个参数是P@ssw0rd的时候输出调用的返回值

2.2 观察异常抛出

有些时候,代码抛出了异常,但是又被另外一个异常包了一层抛出去了,例如throw new RuntimeException(e),甚至有的时候
没有被抛出:log.error(e.getMessage()),导致我们不能看到我们想要的调用栈。

而watch也提供了观察异常抛出的功能。假如有一个Encoder的encrypt方法抛出了一个ExceptionA,但是没有打印栈信息,我们可以用
如下指令:

watch xxx.Encoder encrypt {throwExp} -e -x 2

-e表示抛出异常才触发。
-x表示输出属性的遍历深度,这个是啥意思呢,例如-x的值为1的时候,watch输出的结果可能就只是对象的toString,而-x的值为2的时候,watch也会输出这个对象里面属性的toString,如果等于3,则是对象里面的属性的属性的toString…


随缘更新。。

阅读全文

Docker常用启动参数

Docker 2023/9/4

不定时更新…

达梦8

docker run -d -p 5236:5236 --restart=always --name dm8_01 --privileged=true -e PAGE_SIZE=16 -e LD_LIBRARY_PATH=/opt/dmdbms/bin -e INSTANCE_NAME=dm8_01 -v /data/dm8_01:/opt/dmdbms/data dm8_single:v8.1.2.128_ent_x86_64_ctm_pack4

人大金仓

docker run -d -it --privileged=true -p 54321:54321 -v /opt/docker/kingbase-latest/opt/:/opt --name kingbase-latest godmeowicesun/kingbase:latest
  • 端口: 54321

  • 用户名: SYSTEM

  • 密码: 123456

  • 默认数据库: TEST

mysql

docker run --name mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --privileged -v /home/vagrant/mysql5.7/data:/var/lib/mysql -d mysql:5.7.42

opengauss5.0.0

docker run --hostname=fcdea04e2440 --env=GS_PASSWORD=P@ssw0rd --env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin --env=EXEC_GOSU=gosu-amd64 --env=GOSU_VERSION=1.12 --env=PGDATA=/var/lib/opengauss/data --volume=/var/lib/opengauss/data:/var/lib/opengauss/data --privileged --workdir=/ -p 5432:5432 --restart=no --label='CREATE_DATE=2022-10' --label='GAUSS_SERVER=openGauss-5.0.0' --label='MAIL=heguofeng@huawei.com' --runtime=runc -d opengauss/opengauss:5.0.0

opengauss2.1.0

docker run --name opengauss2.1.0 --privileged=true -d -e GS_PASSWORD=P@ssw0rd -u root -p 5432:5432 enmotech/opengauss:2.1.0

oracel

docker run -d --name oracle-db -p 1521:1521 --privileged -e ORACLE_PWD=123456 -e ORACLE_CHARACTERSET=utf8mb4 -v /opt/oracle/oradata container-registry.oracle.com/database/free:latest

文档

redis

docker run -d --name redis --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis --requirepass 123456 --appendonly yes --port 6381
阅读全文

MySQL迁移到高斯数据库

1. 前言

公司要求项目去适配高斯数据库,看了一下,高斯数据库就可以当做postgresql用,有啥问题把高斯换成postgresql来查就行。
其实整个项目没有太大的变动,只是几个函数需要改一下,如果用mybatis就更简单了:

@Bean
public VendorDatabaseIdProvider vendorDatabaseIdProvider() {
    VendorDatabaseIdProvider vendorDatabaseIdProvider = new VendorDatabaseIdProvider();
    Properties properties = new Properties();
    properties.put("MySQL", "mysql");
    properties.put("Oracle", "oracle");
    properties.put("PostgreSQL", "pgsql");
    properties.put("DM DBMS", "dm");
    vendorDatabaseIdProvider.setProperties(properties);
    return vendorDatabaseIdProvider;
}

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setDatabaseIdProvider(databaseIdProvider());
    factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
    return factoryBean;
}

添加上面配置后,碰到不兼容的函数可以这样处理:

<select id="maxid" databaseId="pgsql" resultType="int">
    select another_max(power_id) from tb_xx
</select>
<!-- 给一个默认的 -->
<select id="maxid" resultType="int">
    select max(power_id) from tb_xx
</select>

这样idea会爆红,可能看着有点不舒服。

也可以考虑这样写:

<choose>
    <when test="_databaseId == 'oracle'">
        xxx
    </when>
    <when test="_databaseId == 'dm'">
        xxx
    </when>
    <when test="_databaseId == 'mysql'">
        xxx
    </when>
    <when test="_databaseId == 'informix' or _databaseId == 'gbase8s'">
        xxx
    </when>
    <otherwise>
        xxx
    </otherwise>
</choose>

两种都可以,如果太复杂了建议用第一种。


本来到这,已经完事大吉了,就去mapper里面去检查一下有没有哪个函数是高斯没有的,然后改一下就行。

结果,万万没想到,项目里面有拿StringBuilder搞SQL拼串的代码,结果写的全是坑,这玩意狠狠折磨了我好几个星期!

2. 别名问题

SELECT id AS userId FROM user

上面这个SQL很简单,就是查用户id,然后起个别名叫userId,乍一看好像没什么,下面我放个图,大家来找不同:

找不同

发现了吗?仔细看一下userId,有没有发现查出来全部变成小写了?

在我们项目代码里,直接从结果集里面拿userId,结果拿不到爆空指针!

原本我以为是配置问题,把大小写搞得不敏感了,结果去网上搜了一下,结果只有表名能修改大小写敏感。

所以要怎么改呢,其实只需要在别名的左右加上双引号就行了:

SELECT id AS "userId" FROM user

这个操作同样兼容mysql。

3. COUNT(*)

SELECT COUNT(*) FROM userId

又是一个非常简单的SQL,然后咱们又来找不同:

高斯的结果:

gs-count

mysql的结果:

mysql-count

相信一眼就能看出来,mysql拿需要用COUNT(*),而高斯则需要用count拿。

这里最好的解决办法就只有取别名了,全部都叫同一个就行了。

不兼容的函数/语法

MySql函数名 高斯函数名 说明
LIMIT offset, size LIMIT size OFFSET offset 高斯不支持mysql的语法,Mysql支持高斯的语法,更换时注意offset和size的位置需要交换
group_concat(col) array_to_string(array_agg(col), ‘,’) group_concat
date_format(col, ‘%Y-%m-%d’) to_char(col, ‘yyyy-mm-dd’) 日期转字符串
delete from tb1, tb2 不兼容,推荐使用子查询 mysql 删除时选择两张表,高斯不支持
IFNULL(xx, fallback) COALESCE(xx, fallback) 当列为空时使用默认值
阅读全文

通过环境变量传递Tomcat https证书密码

2023/8/30

1. 起因

由于最近公司要求给tomcat配置https,本来以为只是简单的塞个证书和私钥就行了:

&lt;Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" &gt;
    &lt;SSLHostConfig protocols="TLSv1.2" sslProtocol="TLS"&gt;
        &lt;Certificate certificateKeyFile="conf/server.key"
                    certificateFile="conf/server.crt"
                    type="RSA"/&gt;
    &lt;/SSLHostConfig&gt;
&lt;/Connector&gt;

结果要求用jks证书文件,彳亍:

&lt;Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" 
    sslProtocol="TLS" 
    protocols="TLSv1.2"
    SSLEnabled="true"
    keystoreFile="conf/server.keystore"
    keystorePass="xxxx"/&gt;

本以为万事大吉,结果甲方爸爸因为密码是直接写的明文,要求我们必须把密码穿成加密的🥲。

不过还好顺带也给了我份博客:tomcat安全配置之证书密码加密存储

2. tomcat配置https

2.1 编写实现类

其实这份博客已经说的很清楚了,只需要继承Http11NioProtocol这个类就可以了

博客里用的Http11Protocol,这个类已经被标记为@Deprecated的了,所以我们直接用它的父类,效果是一样的。

但是这个博客还是不太完整,这个类怎么打jar包?Http11Protocol从哪里来?打了的jar包丢在哪里?博客里都没有说明。

这里我自己研究了一下,首先创建一个maven项目,pom.xml添加依赖:

&lt;dependency&gt;
    &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;
    &lt;artifactId&gt;tomcat-coyote&lt;/artifactId&gt;
    &lt;version&gt;8.5.87&lt;/version&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;

注意scope是provided。

之后就可以直接写代码了:

import org.apache.coyote.http11.Http11NioProtocol;

public class EncryptedHttp11Protocol extends Http11NioProtocol {

    @Override
    public void init() throws Exception {
        // 进行你自己的密码获取逻辑
        setKeystorePass("xxx");
        super.init();
    }

}

写完直接用maven打包:

mvn package -DskipTests

然后丢到tomcat目录的lib文件夹里就可以了。

最后配置server.xml:

 &lt;Connector port="8443" protocol="xxxxxxx.EncryptedHttp11Protocol" SSLEnabled="true"
    keystoreFile="conf/server.keystore"
    sslProtocol="TLS"&gt;
&lt;/Connector&gt;

注意protocol属性要改成你自己的实现类

2.2 设置环境变量

由于jks被加密,需要提供密码,因此推荐的方法是通过系统环境变量来提供(这里直接根据自己的机器设置即可)。
在java代码里这样获取系统环境变量:

String value = System.getenv(key);

2.3 设置命令行参数

也可以通过设置tomcat命令行参数来传输秘钥,
在tomcat的bin目录下创建setenv.bat(windows) / setenv.sh (linux)文件,并且配置相关参数即可。

windows:

set "JAVA_OPTS=-DsecretKey=xxxx -DsercretKey2=xxxx"

linux:

JAVA_OPTS="-DsecretKey=xxxx -DsercretKey2=xxxx"

之后在代码中这样获取:

String value = System.getProperty(key);

3. SpringBoot内嵌tomcat配置https

你说的对,但是我是SpringBoot内嵌tomcat!

公司的众多模块中,偏偏就是有一个SpringBoot项目,这玩意用的内嵌tomcat,上面的方法都用不了👎👎👎。

首先我们要知道SpringBoot项目怎么开启https:

server:
    ssl:
        enabled: true
        key-store: classpath:server.keystore
        key-store-password: xxxxxx

我们只需要找到一个方法在配置ssl前修改配置,提供密码即可。

你别说,还真被我找到了,在启动类添加下面的代码:

@Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> webServerFactoryCustomizer() {
    return factory -> {
        Ssl ssl = factory.getSsl();
        if (ssl == null || !ssl.isEnabled()) {
            return;
        }
        
        // ... 获取秘钥

        ssl.setKeyStorePassword("xxxx");
    };
}

甚至你在这里还可以引用刚才为tomcat准备的jar包,直接使用里面的秘钥获取逻辑,就不用再写一遍了√。

4. 其它:由证书和私钥生成jks文件

首先执行命令生成p12文件(输入后会要求输入密码,直接填上你要的密码就行):

openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12

输完后执行:

keytool -importkeystore -v -srckeystore server.p12 -srcstoretype pkcs12 -srcstorepass 上面的密码 -destkeystore server.keystore -destoretype jks -deststorepass 上面的密码

这里如果jdk版本过低会报错:

keytool 错误: java.io.IOException: parseAlgParameters failed: ObjectIdentifier() -- data isn't an object ID (tag = 48)
java.io.IOException: parseAlgParameters failed: ObjectIdentifier() -- data isn't an object ID (tag = 48)
        at sun.security.pkcs12.PKCS12KeyStore.parseAlgParameters(PKCS12KeyStore.java:816)
        at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2018)
        at java.security.KeyStore.load(KeyStore.java:1445)
        at sun.security.tools.keytool.Main.loadSourceKeyStore(Main.java:2040)
        at sun.security.tools.keytool.Main.doCommands(Main.java:1067)
        at sun.security.tools.keytool.Main.run(Main.java:366)
        at sun.security.tools.keytool.Main.main(Main.java:359)
Caused by: java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 48)
        at sun.security.util.ObjectIdentifier.<init>(ObjectIdentifier.java:257)
        at sun.security.util.DerInputStream.getOID(DerInputStream.java:314)
        at com.sun.crypto.provider.PBES2Parameters.engineInit(PBES2Parameters.java:267)
        at java.security.AlgorithmParameters.init(AlgorithmParameters.java:293)
        at sun.security.pkcs12.PKCS12KeyStore.parseAlgParameters(PKCS12KeyStore.java:812)
        ... 6 more

这里用的jdk1.8.0_241导致的报错,换成jdk-11.0.18可以正常执行,其它版本暂未测试。

阅读全文

svn

2023/5/4

1. 下载安装

下载 · TortoiseSVN

直接下载安装包即可,下载完成后不需要配置环境变量之类的,SVN也不需要你去命令行里去敲哪些什么指令,它自己有很丰富的图形客户端,这点是比GIT好一点点的。

直接对着任意地方右键,如果出现TortoiseSVN的选项,就说明安装成功了(对着桌面按是没有的,需要进随便一个文件夹)。

2. 创建仓库

SVN不支持离线操作,也就是说你想要创建一个仓库,你必须先去服务器支棱一个起来,这里我们直接用码云(工作台 - Gitee.com)就好了。

随便创建一个项目,点击管理 -> 功能设置 -> 启用SVN访问。

之后克隆项目,记得要选SVN的协议:

克隆地址

之后进入任意文件夹,鼠标右键,点击Checkout,之后会弹出来这个:

Checkout

第一个表单就是我们的仓库地址,第二个就是我们要将项目拉到的地方,第三Checkout Depth就是你克隆的深度,你可以选择全部复制(Fully recursive),也可以选择部分,一般配合下面的Choose items按钮使用。

Omit externals表示忽略外部设备,目前不是很清楚有什么用。

最后一个框(Revision)就是版本信息选择了,你可以直接选择最新分支(HEAD revision),也可以通过Show log选择历史分支来进行克隆。

选好后点击OK进行克隆。

3. 提交修改

我们在本地进行任意修改,修改完后在任意子目录或者根目录鼠标右键,在TortoiseSVN选项下找到Commit选项,点开会出现这个:

Commit

最上面的Message就是提交信息,没有什么好说的。

下面那个框就是选择你需要提交的文件。

注意:SVN的Commit会直接提交到服务器,它不是跟Git一样本地提交!!!千万不要乱提交。

下面有个按钮,分别的作用是:

  • Show unversioned files:显示被排除的文件(不受版本控制的文件)

其它的暂时用不上,我们选好后,直接提交,然后再去码云上看,就可以看到提交结果了。

4. 解决冲突

这里我们先在码云上修改一下,然后也在本地修改同样的文件,然后在本地提交:

Commit failed

提交失败了,可以发现它让我们去更新:

You have to update your working copy first

那我们就更新,直接项目目录下右键,点击Update,结果又报错了:

Update failed

可以发现是因为出现了文件冲突,和Git一样,我们需要先解决冲突后再提交。

这里是我本地的文件内容:

hello world
hello world
hello world
hello world

12312
312
3
12
3
12
3
12
3
hello world

这是服务器的:

hello world

12312
312
3
12
3
12
3
12
3
12312
312
3
12
3
12
3
12
3
123312312

这是发生冲突后的文件:

hello world
hello world
hello world
hello world

<<<<<<< .mine
hello world





||||||| .r3
12312
312
3
12
3
12
3
12
3=======
12312
312
3
12
3
12
3
12
3
123312312>>>>>>> .r4

这特么谁看得懂,别急,还记得之前我说过SVN有丰富的图形客户端吗?这里就还真有解决冲突用的玩意:

Edit conflicts

打开后就非常直观了,这里就不放图了,修改完后点击左上角的Save保存,这时它会问你冲突是否已经解决完毕了,如果选择解决完了(Mark as resolved),就可以直接提交了。当然如果又冲突了,就又需要重复上述过程。

5. 代码暂存

待补坑。

阅读全文

Docker

2023/4/20
阅读全文
1 2 3 4
avatar
IceOfSummer

这个人很懒,没有个人简介