1.情况
最近发现内容更新后,刷新内容时,容易出现 500的错误。这个错误在刷新过程中偶尔出现。
## 500
# Internal Server Error.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
通过后台日志看到的输出内容为:
Caused by: java.lang.IllegalStateException: java.lang.OutOfMemoryError: Direct buffer memory [1.4.199/3]
at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.store(MVStore.java:1194) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.commit(MVStore.java:1166) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.compactRewrite(MVStore.java:2169) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.compact(MVStore.java:2041) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.writeInBackground(MVStore.java:2776) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore$BackgroundWriterThread.run(MVStore.java:3123) ~[h2-1.4.199.jar!/:na]
Caused by: java.lang.OutOfMemoryError: Direct buffer memory
at java.base/java.nio.Bits.reserveMemory(Bits.java:175) ~[na:na]
at java.base/java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:118) ~[na:na]
at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:317) ~[na:na]
at java.base/sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:242) ~[na:na]
at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:71) ~[na:na]
at java.base/sun.nio.ch.FileChannelImpl.writeInternal(FileChannelImpl.java:850) ~[na:na]
at java.base/sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:836) ~[na:na]
at org.h2.store.fs.FileNio.write(FilePathNio.java:79) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.DataUtils.writeFully(DataUtils.java:439) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.FileStore.writeFully(FileStore.java:113) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.write(MVStore.java:935) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.storeNow(MVStore.java:1332) ~[h2-1.4.199.jar!/:na]
at org.h2.mvstore.MVStore.store(MVStore.java:1190) ~[h2-1.4.199.jar!/:na]
... 5 common frames omitted
因为缓冲区间内存溢出。都是发生在h2数据库的io请求上的。
如果单纯想扩展运行时分配的内存空间的话,可以通过修改 /etc/systemd/system/halo.service
文件。
ExecStart=/usr/bin/java -server -Xms1024m -Xmx1024m -XX:MaxDirectMemorySize=128m -jar /root/app/halo.jar
保存文件之后,停止halo 服务: service halo stop
然后执行: systemctl daemon-reload
让配置生效。
最后执行:service halo start
等待几秒,服务器启动成功。
就可以解决问题了。
页面刷新出现
java.lang.OutOfMemoryError: Direct buffer memory
的问题得到了显著改善,
但是,H2的数据使用效果的确没有MySQL稳定。特别是随着内容的不断更新,服务器的长时间运行。渐渐感觉H2的操作不太方便,所以就想将数据库进行一次升级操作。
从H2升级到MySQL中来。顺便将Halo从1.5.4升级到1.6.0版本。
1.1 环境
在执行操作前,先简单介绍下我的服务器情况。
- 阿里云ESC 服务器,CentOS 8.0系统。
- 所有环境通过手动安装的,例如Java 11SDK, Nginx,Halo
- Halo 版本为 1.5.4
没有采用Docker镜像安装。服务器无MySQL。
1.2 步骤
我们如果要将现有的网站H2改为MySQL,主要步骤为:
- 通过Halo后台,进行数据备份为json。并将该json文件下载保存。
- 停止Halo 服务器。
- 修改application.yaml 配置文件,将连接服务器从H2改为MySQL。
- 启动Halo服务器,在初始化界面导入json。
注意
- 不用删除你已有的.halo配置目录。
- 更换H2到MySQL 不会造成数据丢失。
- 建议跟换数据库成功之后,再进行Halo升级。
- 建议在更新过程中,暂停服务器的域名访问,可以提高安全性。
2. MySQL配置
2.1 安装 MySQL
(如果已经安装过MySQL,可以跳过这个步骤)
既然要更换,那么就需要先安装好MySQL
第一步更新源: rpm -Uvh http://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm
第二步下载并安装:yum -y install mysql-community-server --nogpgcheck
第三步,查询MySql版本: mysql -V
最后有显示MySQL的版本号,就代表我们安装成功了。
想看详细的安装流程可以参考文章:https://zinyan.com/?p=374 这里就不展开了。
2.2 创建Halo数据库
安装完毕后,通过mysql -uroot -p
进行登录mysql
。
如果你忘记了MySQL的root密码,可以通过https://zinyan.com/?p=471 介绍的方法,找回root密码。
[root@iZufy ~]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.40 MySQL Community Server (GPL)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
然后执行数据库创建指令:create database halodb character set utf8mb4 collate utf8mb4_bin;
具体示例如下:
mysql> create database halodb character set utf8mb4 collate utf8mb4_bin;
Query OK, 1 row affected (0.00 sec)
mysql>
这个时候我们可以执行show databases;
命令看到我们创建的halodb数据库。示例如下:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| halodb |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql>
之后,输入exit退出mysql命令模式。
mysql> exit
Bye
[root@iZufy ~]#
3. Halo配置
当我们将MySQL配置完毕后就开始修改halo的配置信息,将halo的datasource指向我们建立的MySQL。
但要指向之前,需要先将H2数据库中的信息进行备份导出成json。
3.1 H2数据备份
通过Halo后台管理面板,选择系统菜单–小工具选项。在博客备份中选择数据导出。然后点击备份按钮。
将备份后的json文件下载到本地,作为备用操作。
3.2 修改 application.yaml
文档
先暂停Halo,指令为:service halo stop
。执行后根据性能可能会有些反应延时。等一会就好
[root@iZufy ~]# service halo stop
Redirecting to /bin/systemctl stop halo.service
然后修改application.yaml 文件。
[root@iZufy ~]# cd .halo
[root@iZufy .halo]# ls
application.yaml db logs static static_pages templates upload
[root@iZufy .halo]# vim application.yaml
将配置文件中的 H2 database configuration.部分注销,开放 MySQL database configuration.部分。示例如下:
server:
port: 8080
# Response data gzip.
compression:
enabled: true
spring:
datasource:
# H2 database configuration.
# driver-class-name: org.h2.Driver
# url: jdbc:h2:file:~/.halo/db/halo
# username: admin
# password: 123456
#
# H2 database console configuration.
# h2:
# console:
# settings:
# web-allow-others: false
# path: /h2-console
# enabled: false
# MySQL database configuration.
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: 123456
halo:
把H2的相关配置注销,将MySQL的配置添加上去就可以了。
最后,将password 修改为你的root账户的密码就可以了。如果你的数据库创建的不是halodb那么这个地方就修改为自身创建的数据库名。
如果MySQL的端口号不是3306那么你还需要修改这个配置中的端口号。
如果你的MySQL是通过Docker容器部署的,你可以参考Halo官网介绍的指南进行配置。
3.3 导入json包
当配置文件修改完毕后,我们就执行:
[root@iZufy ~]# service halo start
启动当前Halo服务器。
请注意:
1.我们如果在1.5.4版本导出的json。那么也只有1.5.4版本的服务器才能支持json导入。否则会出现版本不匹配无法导入的问题。
2.建议执行更新配置的时候,关闭域名解析。避免其他人在初始化的时候污染我们的配置环境。
重启完毕后,打开我们的服务器会自动重定向到install安装配置界面。我们在该界面中导入我们在第一步获取的H2配置数据。
导入完毕之后,清理浏览器缓存。刷新界面。网站就会恢复正常了。
我们的所有发表数据,配置信息,附件内容等都没有丢失。
那么我们如何判断数据库是切换成功了呢?
很简单:系统后台中的关于界面中原先的数据库:H2 已经变成了 数据库:MySQL了。
3.4 下载最新Halo 1.6 jar包
PS:
建议先进行备份,然后再下载最新Halo 1.6版本包。备份操作可以参考https://zinyan.com/?p=307
建议先执行Json包导入,切换完数据库后再进行更新。(备份json只支持当前Halo版本的导入)
我这里直接更新下载最新的Halo包:
[root@iZufy ~]# cd ~/app && wget https://dl.halo.run/release/halo-1.6.0.jar -O halo.jar
PS: 建议通过GitHub进行下载,最近https://dl.halo.run/release/的下载速度简直太感人了。慢
然后再推送到Linux服务器的
~/app
目录下
下载完毕后,目录样式为:
[root@iZufy app]# ls
halo.jar.1.5.4 halo.jar
[root@iZufy app]#
halo.jar
是我刚才下载的,halo.jar.1.5.4
是我上一个版本的备份文件。
然后执行 service halo start
启动操作。
到这里,更新最新Halo 1.6版本。顺便替换了数据库,从H2改为了MySQL。
4. 其他
H2 可能安装和备份的时候比较方便,数据库完全不用管理。但是当数据量稍微多一些的情况下,还是没有MySQL的性能强。
评论区