Весенняя партия медленно пишет и читает - PullRequest
0 голосов
/ 11 марта 2019

У меня есть пакетное задание для чтения записей из SQLServer и записи в MariaDB. Даже если я реализовал концепцию разделения в пакетном процессе, процесс очень медленный

Ниже приведена конфигурация источника данных дляисходная и целевая системы.

@Bean(name = "sourceSqlServerDataSource")
    public DataSource mysqlDataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setMaximumPoolSize(100);
        hikariDataSource.setUsername(username);
        hikariDataSource.setPassword(password);
        hikariDataSource.setJdbcUrl(jdbcUrl);
        hikariDataSource.setDriverClassName(driverClassName);
        hikariDataSource.setPoolName("Source-SQL-Server");
        return hikariDataSource;
    } 

    @Bean(name = "targetMySqlDataSource")
    @Primary
    public DataSource mysqlDataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setMaximumPoolSize(100);
        hikariDataSource.setUsername(username);
        hikariDataSource.setPassword(password);
        hikariDataSource.setJdbcUrl(jdbcUrl);
        hikariDataSource.setDriverClassName(driverClassName);
        hikariDataSource.setPoolName("Target-Myql-Server");
        return hikariDataSource;
    }

Ниже приведены настроенный My Bean и пул потоков taskexecutor

@Bean(name = "myBatchJobsThreadPollTaskExecutor")
    public ThreadPoolTaskExecutor initializeThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(100);
        threadPoolTaskExecutor.setMaxPoolSize(200);
        threadPoolTaskExecutor.setThreadNamePrefix("My-Batch-Jobs-TaskExecutor ");
        threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(Boolean.TRUE);
        threadPoolTaskExecutor.initialize();
        log.info("Thread Pool Initialized with min {} and Max {} Pool Size",threadPoolTaskExecutor.getCorePoolSize(),threadPoolTaskExecutor.getMaxPoolSize() );
        return threadPoolTaskExecutor;
    }

Здесь настроены шаг и шаг раздела

@Bean(name = "myMainStep")
    public Step myMainStep() throws Exception{
        return stepBuilderFactory.get("myMainStep").chunk(500)
                .reader(myJdbcReader(null,null))
                .writer(myJpaWriter()).listener(chunkListener)
                .build();
    }

    @Bean
    public Step myPartitionStep() throws Exception {
        return stepBuilderFactory.get("myPartitionStep").listener(myStepListener)
                .partitioner(myMainStep()).partitioner("myPartition",myPartition)
                .gridSize(50).taskExecutor(asyncTaskExecutor).build();
    }

Обновление поста с помощью программы чтения и записи

@Bean(name = "myJdbcReader")
    @StepScope
    public JdbcPagingItemReader myJdbcReader(@Value("#{stepExecutionContext[parameter1]}") Integer parameter1, @Value("#{stepExecutionContext[parameter2]}") Integer parameter2) throws Exception{
        JdbcPagingItemReader jdbcPagingItemReader = new JdbcPagingItemReader();
        jdbcPagingItemReader.setDataSource(myTargetDataSource);
        jdbcPagingItemReader.setPageSize(500);
        jdbcPagingItemReader.setRowMapper(myRowMapper());
        Map<String,Object> paramaterMap=new HashMap<>();
        paramaterMap.put("parameter1",parameter1);
        paramaterMap.put("parameter2",parameter2);
        jdbcPagingItemReader.setQueryProvider(myQueryProvider());
        jdbcPagingItemReader.setParameterValues(paramaterMap);
        return jdbcPagingItemReader;
    }

    @Bean(name = "myJpaWriter")
    public ItemWriter myJpaWriter(){
        JpaItemWriter<MyTargetTable> targetJpaWriter = new JpaItemWriter<>();
        targetJpaWriter.setEntityManagerFactory(localContainerEntityManagerFactoryBean.getObject());
        return targetJpaWriter;
    }

Может кто-нибудь пролить свет на то, как повысить производительность чтения-записи с помощью Spring batch ...?

1 Ответ

0 голосов
/ 12 марта 2019

Повышение производительности такого приложения зависит от нескольких параметров (размер сетки, размер чанка, размер страницы, размер пула потоков, размер пула соединений db, задержка между серверами db и вашей JVM и т. Д.). Поэтому я не могу дать вам точный ответ на ваш вопрос, но постараюсь дать некоторые рекомендации:

  • Прежде чем начать улучшать производительность, вам необходимо четко определить базовый уровень + цель. Сказать «это медленно» не имеет смысла. Подготовьтесь, по крайней мере, к профилировщику JVM и клиенту SQL с анализатором плана выполнения запросов. Это необходимо для того, чтобы найти бутылочную горловину производительности либо в вашей JVM, либо в вашей базе данных.
  • Установка размера сетки на 50 и использование пула потоков с размером ядра = 100 означает, что будет создано 50 потоков, но они не будут использоваться. Убедитесь, что вы используете исполнителя задач пула потоков в .taskExecutor(asyncTaskExecutor), а не в SimpleAsyncTaskExecutor, который не использует потоки повторно.
  • 50 разделов для записей по 250 тысяч, мне кажется, много. У вас будет 5000 записей на раздел, каждый раздел даст 10 транзакций (так как chunkSize = 500). Таким образом, у вас будет 10 транзакций x 50 разделов = 500 транзакций между двумя серверами баз данных и вашей JVM. Это может быть проблемой производительности. Я бы порекомендовал начать с меньшего количества разделов, например 5 или 10. Увеличение параллелизма не обязательно означает увеличение производительности . Всегда существует точка безубыточности, когда ваше приложение будет тратить больше времени на переключение контекста и работу с параллелизмом, а не на выполнение своей бизнес-логики. Нахождение этой точки - эмпирический процесс.
  • Сначала я бы запустил любой SQL-запрос за пределами любого задания Spring Batch, чтобы выяснить, есть ли проблема с производительностью самого запроса (запрос захватывает слишком много столбцов, слишком много записей и т. Д.) Или с схема БД (например, отсутствующий индекс)
  • Я бы не использовал JPA / Hibernate для такой работы ETL. Сопоставление данных с объектами домена может быть дорогостоящим, особенно если сопоставление O / R не оптимизировано. Raw JDBC обычно быстрее в этих случаях.

Существует множество других приемов, таких как оценка размера элемента в памяти и проверка того, что общий размер куска в памяти <размер кучи, чтобы избежать ненужного GC внутри куска, выбор правильного алгоритма GC для пакетных приложений и т. Д., Но это как-то продвинуты. Приведенный выше список ориентиров является хорошей отправной точкой для ИМО. </p>

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...