96SEO 2026-02-19 09:28 2
前段时间在做一个数据同步工具其中一个服务的任务是调用A服务的接口将数据库中指定数据请求过来交给kafka去判断哪些数据是需要新增哪些数据是需要修改的。

刚开始的设计思路是,我创建多个服务同时去请求A服务的接口每个服务都请求到全量数据由于这些服务都注册在xxl-job上而且采用的是分片广播的路由策略那么每个服务就可以只处理请求到的所有数据中id%服务总数分片索引的部分数据然后交给kafka由kafka决定这条数据应该放到哪个分区上。
最近学了线程池后回过头来思考认为之前的方案还有很大的优化空间。
1.当数据量很大时一次性查询所有数据会导致数据库的负载过大而使用分页查询每次只查询部分数据可以减轻数据库的负担从而提高数据库的性能和响应速度所以请求数据方每次分页查询少量数据这样可以整体降低请求数据的时间。
第一次优化.之前是每个服务都要把全量数据请求过来假设全量数据1000w条一个服务请求数据需要100s我开5个服务那请求数据的总时长就是500s。
现在把1000w条数据均分给5个服务那1个服务就只需要请求200w条数据耗时20s那所有服务的请求总时长就是100s。
总体耗时缩小了5倍。
上面说的分页查询就可以实现页面大小假设10w也就是将1000w/10w逻辑上分成了100页每个服务自己的分片索引作为页号每次请求完都给索引加上分片总数例如当前注册了五个服务那分片总数5对于分片索引为1的服务来说请求的页号为16111621。
。
。
对于分片索引为2的服务来说请求的页号为271217。
。
。
对于分片索引为3的服务来说请求的页号为381318。
。
。
。
对于分片索引为4的服务来说请求的页号为491419。
。
。
。
对于分片索引为5的服务来说请求的页号为5101520.。
。
这样1000w条数据就均分到每个服务上了。
对于每个服务都是单线程去请求数据就可以将请求操作以及页号总服务数的操作写在一个while循环里一直请求数据直到请求的数据为空时也就是页号超过100了退出while。
HttpUtil.get(remoteURL?pageSize100000pageNumshardIndex);
logger.info(body:{},body);//2.获取返回结果的messageJSONObject
logger.info(name:{},Thread.currentThread().getName());
logger.info(jsonObject:{},jsonObject);//3.从body中获取dataListTestPO
JSONUtil.toList(jsonObject.getJSONArray(data),
TestPO.class);if(CollectionUtil.isEmpty(tests)){break;}shardIndexshardTotal;}第二次优化
了解了线程池后还可以再优化。
之前是一个服务单线程循环请求需要20s假设每次请求10w条需要请求200w/10w也就是20次那一次请求就需要1s。
如果使用线程池的话那么耗时还会更小因为当你将任务都交给线程池去执行时多个线程会同时并行去请求各自页的数据假如你只设置了4个线程那这4个线程会同时发起请求获取数据1s会完成4次请求那分给服务的200w5s就请求完了。
那5个服务从总耗时500s降到了总耗时5s*525s。
一直向线程池里扔请求数据的任务当某个任务请求到的数据是空的时候意味着要请求的数据已经没了那就结束循环不再扔请求数据的任务。
XxlJobHelper.getShardTotal();//分片总数int
AtomicInteger(shardIndex);//多线程情况下
ListCompletableFuturecompletableFutureListnew
pageNum.getAndAdd(shardTotal));JSONObject
JSONUtil.parseObj(body);ListTestPO
JSONUtil.toList(jsonObject.getJSONArray(data),
TestPO.class);logger.info(tests的size:{},tests.size());if(CollectionUtil.isEmpty(tests)){flagfalse;}},executorService);completableFutureList.add(future);}CompletableFuture[]
completableFutureList.toArray(new
CompletableFuture[completableFutureList.size()]);CompletableFuture.allOf(completableFutures).join();logger.info(任务结束);executorService.shutdown();上面代码会有一个问题就是while循环往线程池里扔任务所有线程在执行时会在请求数据那里”停留“一段时间“停留期间”还会一直循环向线程池扔任务当线程执行完某次请求得到空数据结束循环时等待队列中还排着大堆任务等着去请求数据。
为了解决这个问题我改用了for循环提交任务提前根据请求数据总量、每次读取的条数以及服务总数得到每个服务需要执行的任务数。
XxlJobHelper.getShardIndex()1;int
XxlJobHelper.getShardTotal();//分片总数
AtomicInteger(shardIndex);//多线程情况下ListCompletableFuturecompletableFutureListnew
pageSize);logger.info(任务数{},tasks);for(double
i0;itasks;i){CompletableFutureVoid
pageNum.getAndAdd(shardTotal);logger.info(url:{},threadName:{},url,Thread.currentThread().getName());String
JSONUtil.parseObj(body);ListTestPO
JSONUtil.toList(jsonObject.getJSONArray(data),
TestPO.class);logger.info(tests的size:{},tests.size());},executorService);completableFutureList.add(future);}CompletableFuture[]
completableFutureList.toArray(new
CompletableFuture[completableFutureList.size()]);CompletableFuture.allOf(completableFutures).join();logger.info(任务结束);如有问题请求指正(^^ゞ
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback