使用 docker-compose 打包多个应用

准备工作

这次部署两个项目,一个是 web 站点项目,一个是爬虫的后台应用项目。

  1. 两个项目的 jar 包,分别为 app.jar,spider.jar
  2. 两个应用都依赖 redis 和 mysql
  3. mysql 初始化需要的 sql 文件

docker file 文件

docker file 是 使用 docker 部署应用的命令。 具体的命令可以参考 Docker 命令.

由于是两个文件,所以需要两个不同的 Dockerfile .具体的 build 的内容如下:

阅读更多

一个正则表达式导致 CPU 高的问题排查过程

这篇文章记录一个正则表达是导致 CPU 高的问题排查。由于无法直接使用线上的代码测试,所以我自己把代码整理了下来,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class AppMain {
public static void main(String[] args) throws InterruptedException {
final String regex="^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
final String email="blog.laofu.online.fuweilao@vip.qq.com#";
for (int i = 0; i < 1000000; i++) {
Matcher matcher = RegexUtils.matcher(regex, email);
matcher.find();
Thread.sleep(10);
// matcher.group();
}
}
}

当运行程序的时候,我们可以看到 java 的进程占用了 CPU 了 82.1%,由于我使用的服务器是 1核+2G, 所以 load avg 占用也很高。

阅读更多

Linux TOP 命令详解

TOP 命令的含义

TOP 命令是常用的 Linux 性能监控的命令,执行后,界面如下:

image-20200920135205175

第一行

1
top - 14:09:04 up 3 days, 21:20,  0 users,  load average: 0.52, 0.58, 0.59

当前时间(date)、系统已运行时间(last reboot)、当前登录用户的数量(who )、最近5、10、15分钟内的平均负载

阅读更多

简单聊聊 MyCat 分库分表

MyCat 是基于服务器代理模式的数据库分库的中间件,原理是对 SQL 进行转发,具体的架构图如下:

image-20200919120231986

我们知道,数据的拆分必然会对事物的原子性带来影响,那如果保证在分库的同时,又能保证事务的原子性呢?

阅读更多

MySQL 分库分表的方式

对于分库分表来说,具体有两种方式:垂直拆分和水平拆分
垂直拆分主要是业务的细化和独立,和业务联系比较密切。所以本文只讨论更通用的水平拆分。

为什么分库分表

  1. 降低单机 MySQL 的性能
  2. 降低单表或者单库的数据量,减少数据库的查询压力
  3. 突破单机的容量限制
阅读更多

MySQL 索引失效问题

索引失效的情况:

  1. 使用 like ‘%abc’或者like ‘%abc%’
  2. 查询列参与了函数计算(并没有使用函数索引)
  3. 数据不够离散,扫描的行数和加载索引的成本超过了全表扫描
  4. 联合索引没有使用最左匹配,或者在范围运算(>,<,<>)等运算的后面
  5. where中索引列有运算

除了上面的几个明显的问题外,还有索引的选择问题。MySQL 在执行一段 sql 的时候,会先决定使用哪一个索引,如果 选了一个性能比较差的索引,即使走了索引,也会带来性能问题。

对上面的第 4 条做一个例子说明:

  1. 定义 abcd 字段一个联合索引
  2. 如果使用 a>0 and b=1 .. 则 a 本身走索引,但 a 后面的字段都不走索引
  3. a=1 and b=1 and c>1 and d=1 这个例子 只有 d 不走索引,如果 索引顺序更改为 abdc 则都会走索引。
阅读更多

简述 G1 垃圾回收器和 OOM 问题的排查

最近又碰到的 oom 的问题,一直在尝试定位中,由于现实使用的 G1 的垃圾回收器。所以今天打算线上的排查历程和方案查询出来。

jvm 常用参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-Xmx1024m 最大堆内存
-Xms1024m 最小堆内存
-Xss256k 设置栈的大小。栈都是每个线程独有一个,所有一般都是几百k的大小。
-XX:MetaspaceSize=128m 元空间的大小
-XX:MaxMetaspaceSize=256m 最大元空间大小
-XX:MaxGCPauseMillis=200 设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值
-XX:+UseG1GC 使用 G1 垃圾回收器
-XX:-OmitStackTraceInFastThrow 当一些异常在代码里某个特定位置被抛出很多次的话,HotSpot Server Compiler(C2)会用fast throw来优化这个抛出异常的地方。
-XX:MinHeapFreeRatio=30
-XX:MaxHeapFreeRatio=50
-XX:MaxDirectMemorySize=100M 直接内存大小
-XX:+PrintGCDetails 打印 GC 详细信息
-XX:+DisableExplicitGC 禁止显示GC

阅读更多

MySQL 主从同步

为什么需要主从复制

  1. 分别读写数据库的时候,把读和写分开,能够有效的提高数据库的负载
  2. 保证数据的高可用,一旦有一台数据库服务器宕机,不会对数据产生太大的影响
  3. 可以横向扩展,实现数据库的水平扩容

主从同步的原理

主从复制的根本原理是从 master 服务器上面的数据,通过一定的方式同步到 slave 服务器上面。基本过程如下图:

主从复制

  1. 主服务器在修改的数据的时候,会产生一个 bin log
  2. 从服务器上面启动一个 I/O thread,通过配置好的用户名和密码, 连接到主服务器上面请求读取二进制日志,然后把读取到的二进制日志写到本地的一个Realy log(中继日志)里面。
  3. 从服务器上面同时开启一个 SQL thread 定时检查 Realy log(这个文件也是二进制的),如果发现有更新立即把更新的内容在本机的数据库上面执行一遍。

上面的 3 个过程是 MySQL 主从同步的大概流程,其中 binlogrelay log 的读写都是顺序 IO,性能很高。

Relay log转换成数据的过程是一个比较耗时的过程,一般出现了数据延迟的时候,基本都是这里的问题。

搭建主从同步

此处用 Linux 服务器进行演示:

阅读更多

MySQL 事务日志

什么是事务日志?

事务要保证 ACID 的完整性必须依靠事务日志做跟踪:

  1. 每一个操作在真正写入数据数据库之前,先写入到日志文件中

  2. 如要删数据会先在日志文件中将此行标记为删除,但是数据库中的数据文件并没有发生变化。

  3. 只有在(包含多个 sql 语句)整个事务提交后,再把整个事务中的 sql 语句批量同步到磁盘上的数据库文件。

  4. 在事务引擎上的每一次写操作都需要执行两遍如下过程:

    • 先写入日志文件中

      写入日志文件中的仅仅是操作过程,而不是操作数据本身,所以速度比写数据库文件速度要快很多。

    • 然后再写入数据库文件中

      写入数据库文件的操作是重做事务日志中已提交的事务操作的记录

事务日志

事务的日志主要分为三类:redo log,undo logbinlog

日志组

在写日志的时候,单个日志如果过大,对于读写和同步都会产生影响,所以在日志变大的时候,需要对日志进行一个分组。

日志提高事务的效率和安全性保证

  • 用事务日志,存储引擎在修改表的数据的时候,只需要修改其内存,再把该行为记录到持久在磁盘的事务日志中。
  • 事务的日志采用的是顺序追加的方式,采用的是顺序 IO 效率很高
  • 如果发生了崩溃,可以根据 redo log 把数据库恢复到崩溃前的状态。

Redo log

阅读更多

MySQL linux下的安装

  1. 下载包

    1
    https://repo.huaweicloud.com/mysql/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz
  2. 解压

    1
    2
    3
    4
    $ tar -xvf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz 
    # 移动到local/mysql目录下
    $ sudo mv mysql-8.0.20-linux-glibc2.12-x86_64 /usr/local/mysql

  1. 创建 data 目录

    1
    mkdir data
  2. 创建 MySQL 用户 并升级权限

    1
    2
    3
    useradd mysql
    chown -R mysql:mysql /usr/local/mysql
    chmod -R 755 /usr/local/mysql
  3. 初始化

    1
    ./mysqld --initialize --user=mysql --datadir=/usr/local/mysql/data --basedir=/usr/local/mysql

    image-20200823152508875

    注意上面的红框是个初始的登录密码。

  4. 启动并修改密码

    1
    2
    cd support-files
    ./mysql.server start
  5. 连接修改密码

    在连接 MySQL 的时候出现依赖错误。

    1
    ./mysql: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory

    image-20200823152726962

    ​这里是少了一个依赖导致的,可以使用 ldd mysql 来查看 MySQL 对应的依赖:

    image-20200823153059784

    ​从上图中可以看到,其中libtinfog.so.5依赖没有。

    ​这个文件一般在 /etc/lib64/,如果没有需要重现下载,或者拷贝一个。

    image-20200823153649214

    我本地是有的 6.0 ,直接创建一个同步链接就可以了:

    1
    sudo ln -s /usr/lib64/libtinfo.so.6.1 /usr/lib64/libtinfo.so.5
  1. 开始连接

    1
    ./mysql -uroot -p
  2. 修改密码和允许远程连接

    1
    2
    3
    4
    5
    6
    # 修改密码
    mysql>ALTER USER USER() IDENTIFIED BY 'yourpass';
    mysql>flush privileges
    mysql>use mysql;
    msyql>update user set user.Host='%' where user.User='root';
    mysql>flush privileges;
  3. 修改完还是无法连接

    测试是否是防火墙拦截了,先停止防火墙试试

    1
    2
    3
    4
    5
    # 火墙的状态
    $ firewall-cmd --state
    running
    $ systemctl stop firewalld

  4. 停止火墙后能够正常连接,说明是 MySQL 端口没有在防火墙中信任

    1
    2
    firewall-cmd --add-port=3306/tcp --permanent 开放某一个端口号
    systemctl restart firewalld 启动防火墙
阅读更多