Issue
iSTEP Lv2

backend

docker 可通过 【docker logs name --tail 行数】来查看服务的日志

Redis

1. 前端页面显示正常,登入用户时报 “server error”

错误分析

  • 通过本地后端调试发现报错:MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
  • 该错误表示Redis被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用。
  • Redis因为强制重启或宿主机内存不足导致快照未能从内存完整保存至本地,最终造成持久化失败,Redis拒绝写入新数据。
  • 由于登入请求记录无法提交至Redis数据库,导致用户登入失败。

解决方案

  • bgsave: 进行当前数据的异步保存
  • save: 进行当前数据的保存,会阻塞当前请求
  • 如果当前数据丢失,似乎会影响竞赛排名页的更新
  1. 推荐】在/etc/sysctl.conf 添加一项 ‘vm.overcommit_memory = 1’ ,然后运行命令’sysctl vm.overcommit_memory=1’(或者重启)使其生效。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    内存不足:简单说,Redis在保存数据到硬盘时为了避免主进程假死,需要Fork一份主进程,然后在Fork进程内完成数据保存到硬盘的操作,如果主进程使用了4GB的内存,Fork子进程的时候需要额外的4GB,此时内存就不够了,Fork失败,进而数据保存硬盘也失败了。

    而将vm.overcommit_memory改为1有什么作用呢,网上看到一个博客是如下解释:

    0 — 默认设置,当应用进程尝试申请内存时,内核会做一个检测。内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。举个例子,比如1G的机器,A进程已经使用了500M,当有另外进程尝试malloc 500M的内存时,内核就会进行check,发现超出剩余可用内存,就会提示失败。

    1 — 对于内存的申请请求,内核不会做任何check,直到物理内存用完,触发OOM杀用户态进程。同样是上面的例子,1G的机器,A进程500M,B进程尝试malloc 500M,会成功,但是一旦kernel发现内存使用率接近1个G(内核有策略),就触发OOM,杀掉一些用户态的进程(有策略的杀)。

    2 — 当请求申请的内存 >= SWAP内存大小 + 物理内存 * N,则拒绝此次内存申请。解释下这个N:N是一个百分比,根据overcommit_ratio/100来确定,比如overcommit_ratio=50,那么N就是50%。
  2. 推荐与1一起使用】通过redis-cli连接Redis数据库,将stop-writes-on-bgsave-error设置为no,如下。该方法在 因内存不足时造成错误 无法从根源解决问题。

    1
    config set stop-writes-on-bgsave-error no
  3. 不推荐】重启Redis可以临时解决,但很快就会再次报错。

1.1 前端直接连不上后端,Redis设置config set stop-writes-on-bgsave-error no临时解决

Redis报错

  • !! Failed opening the RDB file root (in server root dir /etc/crontabs) for saving: Permission denied

问题分析

通过 config get dir 发现Redis的数据保存位置被篡改为 /etc/crontabs ,该位置为只读文件系统,Redis的操作为不安全操作,没有写入权限,导致保存失败。

解决方案

  1. 通过 config set dir 将目录改回原始存储路径即可解决。

  2. 为Redis设置密码

    1
    2
    3
    4
    5
    config get requirepass  # 查看现有的redis密码

    config set requirepass **** #(****为你要设置的密码)设置redis密码

    # 若出现(error) NOAUTH Authentication required.错误,说明已设置密码,使用 auth 密码 来认证密码
  3. 由于该 Redis 基于 docker 构建,重启后将恢复默认设置!!

    另 Django 的 app/oj/setting.py文件需做如下修改

    image-20210728205741096!!该方法可以实现登入,但在提交问题时会出错

    正确方法如下:

    oj/dev_settings.py: 用于调试环境的配置

    image-20210730142131016 oj/production_settings.py: 用于生产环境的配置

    image-20210730142655656 oj/settings.py: Django 配置 Redis

    image-20210730143136700 docker-compose.yml: 在环境变量中添加 Redis 密码

    1
    2
    docker-compose up -d  # 使 docker-compose.yml 生效【Recreating Done 的 image 无需执行下步】
    docker restart istep-backend # 使修改的 .py 文件生效

TODO

  1. 构建本地 redis.config 文件,使配置永久生效【数据存储位置挂载,设置密码】
  2. 在构建容器时预设定 Redis 密码

2. 警告:WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command ‘echo never > /sys/kernel/mm/transparent_hugepage/enabled’ as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

说明:Redis建议我们关闭THP,以免造成相关问题

解决警告中已给出


其他

smtp 配置不成功

  • OnlineJudge 不支持 ssl,请使用 tls,比如 qq 邮箱是 smtp.qq.com / tls / port 25
  • 部分邮箱 smtp 密码不是登录密码,而是单独的授权密码

忘记用户密码

  • 网页上找回密码
  • 后台用户管理重置
  • 超级管理员等密码也忘记,可以使用下面的命令
1
2
docker exec -it oj-backend /bin/sh
python3 manage.py inituser --username USERNAME --password NEW_PASSWORD --action=reset

CentOS 上部署遇到问题

  • 检查 docker 版本是否太老

  • 关闭 SELinux

查看 Docker 容器运行状态

运行docker ps -a,可以看到以下输出。

1
2
3
4
5
CONTAINER ID        IMAGE                                                        COMMAND                  CREATED             STATUS                       PORTS                                         NAMES
645070877c6c registry.cn-hangzhou.aliyuncs.com/onlinejudge/oj_backend "/bin/sh -c 'sh /app…" About an hour ago Up About an hour (healthy) 0.0.0.0:443->1443/tcp, 0.0.0.0:80->8000/tcp oj-backend
b6fc725b2417 registry.docker-cn.com/library/redis:4.0-alpine "docker-entrypoint.s…" About an hour ago Up About an hour 6379/tcp oj-redis
3402b59b96d3 registry.docker-cn.com/library/postgres:10-alpine "docker-entrypoint.s…" About an hour ago Up About an hour 5432/tcp oj-postgres
7c399af69344 registry.cn-hangzhou.aliyuncs.com/onlinejudge/judge_server "/bin/sh -c '/bin/ba…" About an hour ago Up About an hour (healthy) 8080/tcp judge-server

NAMES就是容器的名称,后面会经常用到。STATUS就是当前容器的运行状态,Up xxx (healthy)就是正常运行状态,unhealthyExited (x) xxx就是退出状态。

注意下面使用 {CONTAINER_NAME} 的地方,都使用对应的名字替换,需要去除大括号。

进入正在运行的容器

然后运行docker exec -it {CONTAINER_NAME} /bin/sh,比如 docker exec -it oj-backend /bin/sh

容器异常退出

容器STATUS显示为Exited(x) xxx,运行docker logs {CONTAINER_NAME},查看错误信息。

docker-compose 启动的时候报错 ‘module’ object has on attribute ‘connection’

尝试运行 pip install --upgrade pip && pip install -U urllib3,然后再重试看看。

Invalid token

请查看docker-compose.yml内的JUDGE_SERVER_TOKENTOKEN是否一致

80 或者 443 端口被占用导致 docker 无法启动

错误信息 bind 0.0.0.0:80 failed, port is already allocated

修改 docker-compose 中 ports 相关的配置,比如 0.0.0.0:80:8080 可以修改为 0.0.0.0:8020:8080,冒号后面的端口号不会冲突请勿改动。

我的浏览器不显示数据或者显示异常

请使用 Chrome 或 Firefox 使用本OJ,如不能解决,请反馈问题。

如何解决 oj 上运行错误但是本地成功的问题

  • 90% 的可能性是代码的bug,本地没有触发,尤其是是本地没有完整测试数据和相同的运行环境的情况下。
  • 如果是 Runtime Error,可能是代码运行过程中 crash,如果提示 signal=31,可能是触发了禁止使用的系统调用。通过 dmesg 可以看到系统调用号。
  • 如果实在想看到代码运行结果,可以修改 docker-compose.yml,去除 judger_debug=1 的注释,然后 docker-compose up -d。重新提交之后,docker exec -it judge-server bash cd /judger/run 就可以看到很多文件夹了,可以找到自己的代码和运行结果。调试完请注释这一行并重新 up -d,否则每次的运行结果都会保留。

如何调整数据库参数

在以下情况下,需要考虑调整数据库参数

  • 机器配置较高,比如 CPU 超过 4 核或内存超过 4G

  • 后端报错数据库连接数不够 too many clients already

    请参考 https://pgtune.leopard.in.ua 选择 DB Version 10,Number of Connections 为 20 倍 CPU 核数,其他的参数按照实际情况填写。

    然后将右侧的参数更新到 OnlineJudgeDeploy/OnlineJudgeDeploy/data/postgres/postgresql.conf 文件中,注意原先配置部分是注释掉的,需要将开头的 # 删除,docker-compose restart oj-postgres 即可。


  • 本文标题:Issue
  • 本文作者:iSTEP
  • 创建时间:2021-08-01 17:15:23
  • 本文链接:https://istep.github.io/2021/08/01/Issue/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论