多线程读取数据库导致连接失败解决方案

问题背景:

某需求需要处理千万级别的数据,按一定规则导出,生成txt或xml文件,单线程处理太慢,写了一个跑了看差不多要处理6~10个小时。想了想还是就用多线程来从数据库中limit不同的数据来进行处理,耗时控制在5分钟以内.相关逻辑为:

 1 //……其他代码
 2 int count = 10000000;//假设共1千万条数据需要读取
 3 int per = 50000;//每次处理5万条
 4 for (int i = 0 ; i < count/per ; i ++){    //创建1000/5=200个线程来处理数据
 5     //使用线程池来处理多线程
 6     ThreadPool.execute(new ProcessTask(i*per,per));
 7 }

 8 //……其他代码
 9 class ProcessTask implements Runnable{
10     int beigin,num;
11     public ProcessTask(int begin,int num){
12         this.begin = begin;
13         this.num = num;
14     }
15     @Overview
16     public void run (){
17     //线程内容,读取数据
18     List<Data> userlist = XXXService.getDataByLimit(begin,num);
19     //……对读出来的数据进行处理
20     //……其他代码
21     }
22 }

可见,此处通过循环同时创建了200个线程,而这200个线程都需要读取数据库,测试环境下最大连接数设置的是20,此时数据库就容易报错,无法连接。

除了无法连接数据库以外,还可能会导致以下问题:

  • 短时间内大量占用服务器内存,导致卡顿,甚至OOM
  • 在线上环境此处大量占用必定引起其他项目的性能
  • 此接口恶意盗刷可能导致服务器直接宕机

解决方案:

对读取数据库操作进行sleep

 1 //……其他代码
 2 int count = 10000000;//假设共1千万条数据需要读取
 3 int per = 50000;//每次处理5万条
 4 for (int i = 0 ; i < count/per ; i ++){    //创建1000/5=200个线程来处理数据
 5     //使用线程池来处理多线程
 6     ThreadPool.execute(new ProcessTask(i*per,per,i));
 7 }
 8 //……其他代码
 9 class ProcessTask implements Runnable{
10     int beigin,num;
11     int i ;
12     public ProcessTask(int begin,int num,int i ){
13         this.begin = begin;
14         this.num = num;
15         this.i = i ;
16     }
17     @Overview
18     public void run (){
19     //线程内容,读取数据
20     Thread.sleep(i*500);//可以改成更大的值
21     List<Data> userlist = XXXService.getDataByLimit(begin,num);
22     //……对读出来的数据进行处理
23     //……其他代码
24     }
25 }

这样处理后就可以分时的读取数据库,减少服务器的负担,但是时间会变长(sleep操作),200*0.5=100s,不过也是在可以接受的范围内。

感觉好像也没多少技术含量……或者说把getDataByLimit方法设置成synchronizd就行了吧,如果是单独使用的情况下……

<--EOF-->

时间: 2024-10-16 10:11:02

多线程读取数据库导致连接失败解决方案的相关文章

Nginx反代,后端一个IP绑定多个SSL证书,导致连接失败之解决方法:HTTPS和SNI扩展

默认:SSL协议进行握手协商进行连接的时候,默认是不会发送主机名的,也就是是以IP的形式来进行https连接握手协商的,这就导致一个问题,当一台服务器上有多个虚拟主机使用同一个IP的时候, Nginx进行反代就会报错! SNI(Server Name Indication):就是为了解决一个服务器,同一个IP,使用多个域名证书的情况,也就是使用SSL连接服务器的时候,先发送访问的站点域名,这样服务器就会根据域名返回一个合适的证书. Nginx开启SNI: proxy_ssl_server_nam

数据库远程连接失败

在开发的过程中,数据有时候并不是放在本地机器上,这时候我们就需要从远程服务器获取数据.我碰到一种情况,通过Sql工具可以链接到远程服务器的数据库,同样也可以查询数据,但是在项目中就是没有办法获取,抛出“拒绝访问"的异常. 我的解决办法是重启一下winsock ,具体如下: 1.打开cmd 2.输入命令:netsh winsock reset

谷歌公共库(ajax.googleapis.com)、谷歌字体库(fonts.googleapis.com)连接失败解决方案

由于谷歌服务器退出中国,无法正常使用谷歌公共库CDN服务,造成很多网页无法查看.幸运的是火狐浏览器和360给我们提供了解决方案: 1.下载并安装火狐浏览器http://download.firefox.com.cn/releases/stub/official/zh-CN/Firefox-latest.exe 2.打开火狐浏览器:打开菜单—>附加组件—>搜索mason组件—>安装mason组件,重启火狐浏览器 3.在电脑内新建txt文件,保存以下内容 <mason> Char

oracle由于ip地址改变导致连接失败

emmmm,改了一晚上没有改好,网上说的好多方法试过之后根本不管用,于是在一个大佬的博客下看到了,才将错误改好. 主要是修改两个配置文件,listener.ora和tnsnames.ora,路径......自己找吧. 文章链接:https://blog.csdn.net/ludongshun2016/article/details/53130102 反正就是傻瓜式整体修改了这两个文件,好用了,具体原因和修改的理由等以后深入了解了在回来添加吧,睡了,命要紧. 原文地址:https://www.cn

nf_conntrack限制导致服务器连接失败

发现客户端在连接java服务时出现失败的情况,查看系统日志发现大量 kernel: nf_conntrack: table full, dropping packet. kernel: nf_conntrack: table full, dropping packet. kernel: nf_conntrack: table full, dropping packet. 从日志可以看出,由于开启了iptables,iptalbes会使用nf_conntrack模块跟踪连接,而这个连接跟踪的数量是

Mysql容器启动失败-解决方案

在看问题之前首先熟悉几个命令 相关命令 1.docker attach 连接到正在运行中的容器: 命令:docker attach --sig-proxy=false mynginx 2.docker exec 这个命令比较方便,可以在容器运行别的服务时连接上该容器: 命令:docker exec -it mysql_database1 /bin/bash 3.docker inspect mysql 查看容器的详细信息: 命令:docker inspect mysql 4.docker com

sharepoint 2013 打开rdl报表,报表服务器数据库内出错。此错误可能是因连接失败、超时或数据库中磁盘空间不足而导致的

 最近在做reporting services报表的时候,部署到sharepoint后,打开rdl报表,经常遇到一个问题: 报表服务器数据库内出错.此错误可能是因连接失败.超时或数据库中磁盘空间不足而导致的. ---> Microsoft.ReportingServices.Diagnostics.Utilities.ReportServerStorageException: 报表服务器数据库内出错.此错误可能是因连接失败.超时或数据库中磁盘空间不足而导致的. ---> System.Da

Robomongo 0.9.0 连接mongo数据库时,提示连接失败 的解决方案

Robomongo 0.9.0 连接mongo数据库时,提示连接失败.(IP和端口号确定是对的) 基本注意点: 1.mongodb服务打开,打开时,指定端口号,默认为27017,使用默认值,则不用指定.2.防火墙关闭或是允许端口(6666)通过防火墙3.认证的情况下,数据库连接和用户名,密码要匹配.数据库和用户的对应关系,可以在系统数据库system.admin中的集合system.users中查看

Laravel 命令行工具之多线程同步大批量数据 DB连接混乱 解决方案

记一次大批量数据的多进程同步 背景:因为公司的用户标识不完整,所以需要从集团同步一次用户标记数据,用户数据来源是微信,数量级为一百五十万,集团用户数量级为六百万 方案确定下来是集团开了一个查询接口,访问没有频率并发限制,数量级在那呢,我们遍历公司的用户,去查询这些用户的标识来更新 项目使用了laravel,就写了一个命令行脚本,开15个进程去跑 由于时间关系使用了PHP的pcntl_fork实现多进程 核心代码如下: 主要流程是: 首先主进程分配userid给各个子进程,这里使用了redis队列