0%

问题复现

假设线上是一个典型的Spring Boot Web项目,某一块业务的处理逻辑为:

接受一个name字符串参数,然后将该值赋予给一个注入的bean对象,修改bean对象的name属性后再返回,期间我们用了 Thread.sleep(300) 来模拟线上的高耗时业务

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
@RequestMapping("name")
public class NameController {

@Autowired
private NameService nameService;

@RequestMapping("")
public String changeAndReadName (@RequestParam String name) throws InterruptedException {
System.out.println("get new request: " + name);
nameService.setName(name);
Thread.sleep(300);
return nameService.getName();
}

}

上述的nameService也非常简单,一个普通的Spring Service对象

具体代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class NameService {

private String name;

public NameService() {
}

public NameService(String name) {
this.name = name;
}

public String getName() {
return name;
}

public NameService setName(String name) {
this.name = name;
return this;
}
}

相信使用过Spring Boot的伙伴们对这段代码不会有什么疑问,实际运行也没有问题,测试也能跑通,但真的上线后,里面却会产生一个线程安全问题

不相信的话,我们通过线程池,开200个线程来测试NameController就可以复现出来

阅读全文 »

前阵子写过一篇文章,用来记录如何在docker中启动ZooKeeper的单机或者集群节点,最近收到一个issue,大意是说项目启动后,测试ZK的四字命令无效,这篇文章记录一下解决办法

ZK四字命令

四字命令其实就是通过类似 echo stat | nc 127.0.0.1 2181 这样的指令,来与zk节点交互,获取或者设置数据的指令

zk四字命令列表:

命令 示范 解释
conf echo conf | nc 127.0.0.1 2181 输出相关服务配置的详细信息。比如端口、zk数据及日志配置路径、最大连接数,session超时时间、serverId等
cons echo cons | nc 127.0.0.1 2181 列出所有连接到这台服务器的客户端连接/会话的详细信息 包括“接受/发送”的包数量、session id 、操作延迟、最后的操作执行等信息
crst echo crst | nc 127.0.0.1 2181 重置当前这台服务器所有连接/会话的统计信息
dump echo dump | nc 127.0.0.1 2181 列出未经处理的会话和临时节点(只在leader上有效)
envi echo envi | nc 127.0.0.1 2181 输出关于服务器的环境详细信息(不同于conf命令),比如host.name、java.version、java.home、user.dir=/data/zookeeper-3.4.6/bin之类信息
ruok echo ruok | nc 127.0.0.1 2181 测试服务是否处于正确运行状态。如果正常返回”imok”,否则返回空
srst echo srst | nc 127.0.0.1 2181 重置服务器的统计信息
srvr echo srvr | nc 127.0.0.1 2181 (New in 3.3.0)输出服务器的详细信息。zk版本、接收/发送包数量、连接数、模式(leader/follower)、节点总数
stat echo stat | nc 127.0.0.1 2181 输出服务器的详细信息:接收/发送包数量、连接数、模式(leader/follower)、节点总数、延迟。 所有客户端的列表
wchs echo wchs | nc 127.0.0.1 2181 列出服务器watches的简洁信息:连接总数、watching节点总数和watches总数
wchc echo wchc | nc 127.0.0.1 2181 通过session分组,列出watch的所有节点,它的输出是一个与 watch 相关的会话的节点列表。如果watches数量很大的话,将会产生很大的开销,会影响性能,小心使用
wchp echo wchp | nc 127.0.0.1 2181 通过路径分组,列出所有的 watch 的session id信息。它输出一个与 session 相关的路径。如果watches数量很大的话,将会产生很大的开销,会影响性能,小心使用
mntr echo mntr | nc 127.0.0.1 2181 列出集群的健康状态。包括“接受/发送”的包数量、操作延迟、当前服务模式(leader/follower)、节点总数、watch总数、临时节点总数

Docker容器中的ZooKeeper不响应四字命令

随着ZooKeeper的官方Docker镜像推出,大家也都纷纷按照官方介绍的那样,用Docker来运行ZooKeeper,开始用着很爽,直到有人发现四字命令出问题:“输了命令没有响应”

百度谷歌各家论坛也没有找到解决办法,直到认真翻了一遍ZooKeeper的官方文档:zookeeper-doc

才发现,使用Docker镜像启动的ZK容器,默认是没有配置四字命令白名单列表的,说白了,你只有在这个docker容器内部才能使用四字命令,而到了宿主机上,则会被禁止掉,所以就会出现无响应这种问题

那么解决办法也很简单,我们可以利用volumes指令,在宿主机上配置好zk镜像,再映射到容器中来启动zk即可解决

阅读全文 »

项目案例代码:github/h2db

H2是一个纯Java开发的嵌入式数据库,它可以作为内存数据库将数据保存在内存中,也可以持久化保存在硬盘中

H2最主要的一个特征在于它足够轻,轻到只用一个jar包便可以启动

1
2
3
4
5
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
</dependency>

以Mysql为例,传统的数据库要启动一般包含下面几个步骤

  • 下载安装Mysql

  • 建库建表

  • 创建应用、设置源地址、建立连接并编码

而H2可以省略安装的操作,并且极大简化建库建表跟编码的工作

咋一看,好像没啥特别的作用,但在下面这几个应用场景中还是用h2最为合适

  • 案例型项目:纯粹为了验证某一种技术方案可行性而编写的demo项目

  • 各种项目下的测试单元:测试单元如果涉及到数据库的操作,那么这种情况下使用h2并将数据临时存储在内存种是最合适不过的

  • client-server类型的项目

H2作为一款嵌入式数据库,同时支持两种运行模式:In-memory DataBae与Persisted Database

阅读全文 »

先前发布的solo-in-docker项目支持各位黑客派会员一键部署solo项目,但遗憾的是只支持http协议,今天发布的v1.3.0版本全部支持https协议

项目地址: github/solo-in-docker

同时感谢 @Fly 大佬提供的支持

1. HTTP部署

  • clone项目,cd http进入http目录

  • 按照http目录下的readme配置docker-compose,只需要修改自己的域名跟端口

  • 启动,结束(启动、结束、查看日志等命令请参考http目录下的readme)

2. HTTPS部署

  • 请自行获取ssl数字证书

  • clone项目,cd https进入https目录

  • 按照https目录下的readme配置nginx.conf与docker-compose,前者是让nginx找到证书,后者是修改自己的域名跟端口

  • 启动,结束

3. 先部署HTTP再升级HTTPS

对于一些老用户,可能您之前用的http方式部署的项目,现在想升级到https的话,只需要做两件事情

  • 按照https目录下的readme获取证书、配置

  • 将老项目的mysql/data目录复制替换到https的mysql/data目录即可

阅读全文 »

Let’s Encrypt是一款永久免费的SSL通配符证书,这篇文章介绍如何使用acme.sh来获取它

acme.sh项目地址: acme.sh

官方中文文档地址: acme.sh/wiki

DNS解析验证

获取证书,需要验证站点确实是归本人所有,常用的验证方式一般是通过DNS解析一条TXT记录来完成

ACME提供两种方式,一种是不指定DNS运营厂商,我们自己去修改txt解析记录即可,另外一种是指定CloudFlare,也就是说您的域名DNS解析地址要由CloudFlare提供

经过实际测试,前者获取到的证书在浏览器上会被标识为不安全,而后者却会被标识为安全

不指定DNS运营产商

首先输入以下命令获取txt记录值:

1
~/.acme.sh/acme.sh --issue -d liumapp.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
阅读全文 »

Mysql中,只要表中存在longblob或者longtext类型的字段,并且数据量一多,那么对这张的查询操作将会变得非常缓慢,但使用单列索引就可以解决此类问题

问题重现

现在mysql中有一张表,假设名为 imgs ,一共三个字段,id, mid, fileData,其中id为主键,mid为关联表id,fileData为一个longBlob类型的字段

现在我们用脚本或者代码随机往imgs表中插入10w条左右的数据,再运行由mybatis生成的查询sql:

1
select 'true' as QUERYID, id, mid, fileData from imgs WHERE ( mid = 1257 )

那么不出意外,运行这段sql所需要的时间将会是非常高昂的成本(在我本地测试用了足足5秒)

对应到线上环境,5秒的查询时间是不可能被允许的,必须优化

创建单列索引

我们可以分析,如此缓慢的查询,其本质原因就是因为longBlob字段造成的开销影响的,如果可以在查询之初就迅速定位一个较小的范围,那么就可以解决这个问题

而索引恰恰就能够完美的解决: 如果我们对mid创建索引index,那么mysql能够通过where mid = 1257迅速把搜索范围定位到mid = 1257的范围内,然后再去根据其他搜索条件去查找

阅读全文 »

基于libreoffice实现的文档转换项目,无框架依赖,即插即用

项目源代码:github/workable-converter

1. 技术栈

  • LibreOffice:v6.2.3

  • jodconverter:4.2.2

  • PDFBox:2.0.12

  • cglib动态代理 + 懒汉工厂模式 + 策略模式 + 装饰器模式

  • qtools-property管理配置文件(application.yml、bootstrap.yml、workable-converter.yml三种命名的配置文件任意包含一种即可)

2. 功能

  • 支持doc、docx、html、ppt、png、pdf等等类型的文件互相转换

  • 支持按照文件路径、字节输入输出流、Base64等不同姿势转换

  • 不依赖第三方框架,即插即用,支持application.yml、bootstrap.yml、workable-converter.yml三种配置(自己项目中具体配置一个即可)

3. 使用

3.1 安装配置LibreOffice6.2.3

CentOS请直接参考这篇文章:CentOS7安装LibreOffice6.2.3

阅读全文 »

Maven与Gradle相信大家非常清楚,但是fat-jar是个什么鬼?长得比较胖的jar包吗?没错,就是比较胖的jar包…这篇文章介绍如何在Maven跟Gralde中构建这些胖子jar包❤️

首先上项目源代码:

Fat-Jar

用过大红大紫的SpringBoot,就知道它的打包结果就是一个Fat-Jar: 将项目代码以及所依赖的第三方Jar包,全部打包到一个Jar包中即为Fat-Jar技术~

具体使用哪种Fat-Jar实现方式,一般而言根据我们所使用的依赖管理工具来决定,这里我们举Gradle跟Maven这两个最常见的依赖管理工具来举例

Gradle-plugin: shadowJar

如果我们是使用的Gradle来构建项目,那么可以使用shadowJar这一款plugin来将项目打包为一个”胖子jar包”

案例代码:

在项目的build.gradle中添加以下代码:

阅读全文 »

在CentOS7上安装LibreOffice6.2.3、配置中文字体、实现对office系列文档转PDF操作的排坑记录

操作步骤

  • 获取LibreOffice6.2.3以及中文字体的rpm下载包

  • 在服务器上解压LibreOffice_6.2.3_Linux_x86-64_rpm.tar.gz与LibreOffice_6.2.3_Linux_x86-64_rpm_langpack_zh-CN.tar.gz

    解压安装LibreOffice_6.2.3

    • tar -xvf LibreOffice_6.2.3_Linux_x86-64_rpm.tar.gz

    • 得到一个名为LibreOffice_6.2.3.2_Linux_x86-64_rpm的文件夹

    • 进入RPM包目录:cd ./LibreOffice_6.2.3.2_Linux_x86-64_rpm/RPMS

    • 使用yum localinstall批量安装rpms包: yum localinstall *.rpm

      解压安装中文字体支持包

    • tar -xvf LibreOffice_6.2.3_Linux_x86-64_rpm_langpack_zh-CN.tar.gz

    • 得到一个名为LibreOffice_6.2.3.2_Linux_x86-64_rpm_langpack_zh-CN的文件夹

    • 进入RPM包目录: cd ./LibreOffice_6.2.3.2_Linux_x86-64_rpm_langpack_zh-CN/RPMS/

    • 使用yum localinstall批量安装rpms包: yum localinstall *.rpm

      但经过实际测试,仅仅安装官方的中文字体包还是不够,很多时候我们要转换的中文doc文件,用到的字体文件都是windows系统下面的中文字体,所以保险起见,我们最好把windows系统下面的中文字体安装到CentOS上

      操作步骤大家可以参考我的这篇文章: CentOS7服务器安装中文字体

  • 安装成功后,使用命令 which libreoffice6.2查看可执行文件位置,不出意外应该结果应该是 /usr/bin/libreoffice6.2

    或者使用命令 ll /usr/bin/libreoffice6.2 查看具体安装位置,不出意外结果应该是 /usr/bin/libreoffice6.2 -> /opt/libreoffice6.2/program/soffice

  • 测试libreoffice6.2是否运行正常

    • 上传一个test.doc文档到服务器上,假设文件目录为 /usr/src/test.doc

    • 执行命令开始将test.doc转换为test.pdf

      1
      libreoffice6.2 --headless --invisible --convert-to pdf /usr/src/test.doc --outdir /usr/src
    • 不出意外的应该会报以下错误:

      1
      /opt/libreoffice6.2/program/soffice.bin: error while loading shared libraries: libcairo.so.2: cannot open shared object file: No such file or directory

      原因是libcairo.so.2这个库找不到,我们下载安装就可以了

      安装命令如下

      请依次执行

      1
      2
      3
      yum install cairo -y
      yum install cups-libs -y
      yum install libSM -y
    • 再次执行命令

      1
      libreoffice6.2 --headless --invisible --convert-to pdf /usr/src/test.doc --outdir /usr/src

      转换成功,结束

阅读全文 »