从API

时间:2016-01-21 14:23:09

标签: java mysql multithreading performance api

我正在使用this API从中检索大约24.000个项目。

首先,我从here获取项目列表(警告,慢速浏览器可能会崩溃)。

然后我遍历所有项目并找到每个项目的所有信息。类似的东西:

https://api.guildwars2.com/v2/items/itemidhere

并将信息插入MySQL数据库。

PD:真正的问题在下面的这一行之后开始。

我试图找到从这些链接获取信息并插入信息的最快方法。为此我正在使用:

-GSON库(控制JSON的最简单,最快捷的方式)
-HikariCP(用于数据库连接池)
-Threads(如果有24个线程,每个线程会处理1000个项目)

我做了一些测试,以下是收集和插入24.000项的结果:

-Threads:50
-DB池大小:10
- 时间:644秒

-Threads:100
-DB池大小:10
- 时间:607秒

-Threads:250
-DB池大小:15
- 时间:662秒

-Threads:500
-DB池大小:20
- 时间:689秒

我知道这里最慢的是网络 我的电脑和互联网都不慢:
-300mb / s互联网
enter image description here
-Intel 5820k
-16GB DDR4

所以剩下的可能是代码实现......

    HikariConfig config = new HikariConfig();
    config.setDriverClassName("com.mysql.jdbc.Driver");
    config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
    config.setUsername("root");
    config.setPassword("none");
    config.addDataSourceProperty("cachePrepStmts", "true");
    config.addDataSourceProperty("prepStmtCacheSize", "250");
    config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
    config.setMaximumPoolSize(depending on case);
    Core.ds = new HikariDataSource(config);

这是数据库连接池的设置。我使用Cyclic屏障启动线程:

    final CyclicBarrier _threadGate = new CyclicBarrier(depends on case);
    ArrayList<Thread> _threadList = new ArrayList<>();

然后

     _threadList.add(new Thread() {
            @Override
            public void run() {
                try {
                    _threadGate.await();
                    //Parsing happens a bit later

这里我遍历所有列表并从url获取信息(我跳过变量声明):

                        _id = _itemList.get(i);
                        _stringUrl = "https://api.guildwars2.com/v2/items/" + _id;
                        _responseText = new URL(_stringUrl);
                        _requestUrl = (HttpURLConnection) _responseText.openConnection();
                        _requestUrl.connect();
                        _requestStatus = _requestUrl.getResponseCode();
                        if(_requestStatus == 200){
                           _jsonParser = new JsonParser();
                            _rootElement = _jsonParser.parse(new InputStreamReader((InputStream) _requestUrl.getContent(), "UTF-8"));
                            _rootObject = _rootElement.getAsJsonObject();

来自_rootObject进行大量解析并检查json是否退出等等......最后插入......

以下是在主类中处理完所有内容后启动线程的方法:

    for (int i = 0; i < _threadList.size(); i++) {
        _threadList.get(i).start();
    }

INFO:here关于为什么我没有使用更大的池大小。

我不明白的是:
- 为什么如果有更多的线程,结果会更慢 - 我的意思是,cmon也许网络很慢,但是很少有请求可以填满300mb / s? - 实现更好的代码会使这更快吗?

我实际上是这样看的:
- 更多主题 - &gt;互联网速度较慢,这使得拉动信息变慢 - 较大的泳池大小 - &gt;由于许多连接而插入较慢
- 更多线程和小连接池 - &gt;插入排队和停滞的 -few线程和小连接池 - &gt;慢拉信息

更新
池中的经典连接,1个连接/池,结果较慢,比较慢30秒
在CyclicBarrier上执行ExecutorService,结果慢了10秒。

1 个答案:

答案 0 :(得分:0)

(“评论”的问题太多了。)

我很困惑 - 你正在“检索数据”而你正在“插入”它。我们应该关注哪一方?你控制哪一方?

您每秒只能插入30-40行?那太可悲了。

让我们关注你如何在MySQL表中执行INSERTs。请提供SHOW CREATE TABLE - 我需要查看引擎和索引以及其他内容。请提供一些关于INSERTs的线索 - 一次一行vs批次(这里改进10倍)?顺序与随机PRIMARY KEY?桌子有多大? buffer_pool有多大?什么版本的MySQL(较新的版本有一些额外的技巧)?

线程之间存在一些争用,因此“太多”线程实际上可以减慢活动速度。但我认为这是次要问题。

消耗306Mb / s的百分之几?