paint-brush
Миграция бизнес-логики выполняется быстрее, чем заваривается кофек@ispirersystems
448 чтения
448 чтения

Миграция бизнес-логики выполняется быстрее, чем заваривается кофе

к Ispirer Systems17m2023/11/10
Read on Terminal Reader

Слишком долго; Читать

В этой статье подробно описан проект, в котором Ispirer помог финансовой консалтинговой компании перейти с Microsoft SQL Server на Java, оптимизировать архитектуру системы и снизить затраты на обслуживание. Клиент стремился перенести бизнес-логику на уровень приложения, передав 815 000 строк кода (LOC) и 300 ГБ данных в PostgreSQL. Автоматизация была ключом к минимизации затрат на миграцию: Ispirer Toolkit был заранее настроен для достижения коэффициента конверсии 90%. Процесс миграции включал преобразование схемы и данных, настройку ограничений и триггеров, оптимизацию производительности, проверку данных и согласование настроек безопасности. В статье также освещаются причины перемещения бизнес-логики на уровень приложения, уделяя особое внимание масштабируемости, удобству сопровождения, простоте разработки и возможности повторного использования. Примеры преобразований кода, такие как инструкции INSERT, наборы с несколькими результатами, метод DATEDIFF, метод sp_send_dbmail и методы, связанные с XML, демонстрируют эффективность автоматизации. Усилия по настройке значительно ускорили миграцию, сократив общее время в четыре раза по сравнению с миграцией вручную. В заключении подчеркиваются стратегические преимущества перехода с Transact-SQL на Java, обеспечивающие большую гибкость, кросс-платформенную совместимость и масштабируемость для организаций, стремящихся к модернизации.
featured image - Миграция бизнес-логики выполняется быстрее, чем заваривается кофе
Ispirer Systems HackerNoon profile picture

Как мы автоматизировали миграцию SQL Server на Java и ускорили миграцию в 4 раза


Данная статья посвящена модернизации Microsoft SQL Server на основе проекта, выполненного Ispirer для крупной компании, занимающейся финансовым консалтингом. Клиент использовал возможности базы данных SQL Server для эффективной обработки, обработки, доступа и контроля финансовой информации своих клиентов. Клиент стремился перенести SQL Server в облако, оптимизируя при этом системную архитектуру и затраты на обслуживание.


Команда Ispirer предложила перенести бизнес-логику на Java, поскольку база данных используется в режиме OLTP. Мы тщательно проанализируем тему и рассмотрим проект клиента, который предполагает конвертацию бизнес-правил SQL Server в Java. Кроме того, мы выясним причины, по которым компании решили перенести код SQL на уровень приложений. Это потребует комплексного изучения всего процесса.


Чтобы оптимизировать затраты на облачную инфраструктуру, клиент решил перенести таблицы и данные в PostgreSQL. Поскольку мы специализируемся на миграции баз данных и приложений, заказчик обратился к нам со следующими задачами:


  • Перемещение 815 000 LOC бизнес-логики на уровень приложения в Java.
  • Миграция 300 ГБ данных и 3000 таблиц с Microsoft SQL Server на PostgreSQL.


Ввиду значительного масштаба проекта клиент постарался минимизировать затраты на миграцию за счет внедрения автоматизации. Чтобы оптимизировать эффективность Ispirer Toolkit, мы решили, что его настройку следует провести заранее. Такой подход позволил нам предоставить команде клиента инструмент с коэффициентом конверсии T-SCL в Java примерно 90%.


Теперь давайте углубимся в миграцию таблиц и данных.


С SQL Server на PostgreSQL: миграция данных и таблиц


Давайте рассмотрим причины, по которым клиент решил перейти с локального SQL Server в облако. Этот переход включает в себя ряд неоспоримых преимуществ:


  1. Экономия затрат. Одним из основных движущих факторов перехода с SQL Server на PostgreSQL в облаке является экономия средств. Раньше клиент считал, что хранить базы данных SQL Server на месте дорого. Это было связано с необходимостью специального оборудования, лицензий на программное обеспечение и квалифицированных администраторов баз данных. PostgreSQL, будучи базой данных с открытым исходным кодом, предлагает экономичную альтернативу. Клиенты могут сэкономить деньги, используя облако. Им придется платить только за то, что они используют, вместо того, чтобы вносить большие авансовые платежи. Кроме того, они могут тратить меньше средств на операции.


  2. Масштабируемость. Облачные вычисления легче масштабировать, чем локальную инфраструктуру, для обслуживания больших рабочих нагрузок и большего числа пользователей. Чтобы локальная система могла масштабироваться в соответствии с потребностями бизнеса, организациям пришлось приобрести и установить физические серверы, лицензии на программное обеспечение, хранилище и сетевое оборудование для масштабирования бизнес-услуг в традиционных ИТ-средах. В облаке большинство этих ресурсов доступны мгновенно, в несколько кликов, и их можно автоматически увеличивать и уменьшать в зависимости от необходимых ресурсов. PostgreSQL в облаке обеспечивает высокий уровень масштабируемости, позволяя нашему клиенту легко настраивать ресурсы в зависимости от спроса.


  3. Безопасность. Использование облачных технологий предлагает заметные преимущества в области безопасности благодаря расширенным средствам контроля идентификации, управлению доступом и системам аутентификации, предоставляемым поставщиками облачных услуг. Часто поставщики облачных услуг имеют более высокие стандарты безопасности, чем собственные ИТ-команды или локальные системы, что делает среду данных более безопасной.

    Надежное шифрование в облаке снижает вероятность утечки данных. Он включает в себя многоуровневую безопасность, хорошее управление ключами и безопасный контроль доступа, которые помогают предприятиям эффективно контролировать доступ пользователей. Более того, поставщики облачных услуг строго контролируют физический доступ, внедряя такие меры, как анонимность, репликация и шифрование, для усиления защиты данных. Прогнозируется, что к 2025 году около 80% предприятий перейдут от физических центров обработки данных к облачным сервисам. Этот сдвиг обусловлен улучшенными преимуществами безопасности, предоставляемыми облаком.


Переход с SQL Server на PostgreSQL в облаке требует тщательного планирования и выполнения с учетом конкретных соображений. На основе проекта клиента наша команда выделила следующие этапы модернизации SQL Server:


  1. Схема и преобразование данных. Данные должны быть точно преобразованы, чтобы соответствовать требованиям PostgreSQL. Это может включать обработку таких нюансов, как форматы дат и кодировка символов.


  2. Ограничения и триггеры. Понимание различий в использовании ограничений и триггеров в двух базах данных имеет решающее значение. Соответственно необходимо внести необходимые изменения. Кроме того, функционал триггеров можно перенести в приложение. Однако задача эта далеко не простая, поэтому важно взвесить все «за» и «против».


  3. Оптимизация производительности. Оптимизация процесса миграции позволяет минимизировать простои и время передачи данных. Для эффективной миграции важно использовать распараллеливание, оптимизировать пропускную способность сети и инвестировать в мощное оборудование.


  4. Проверка данных и тестирование. Чтобы гарантировать целостность и функциональность данных, необходима строгая проверка перенесенных данных. Всестороннее тестирование гарантирует бесперебойную работу приложений с новой базой данных PostgreSQL.


  5. Безопасность и разрешения. Параметры безопасности, учетные записи пользователей и разрешения в PostgreSQL должны быть настроены в соответствии с исходной настройкой SQL Server, обеспечивая плавный переход.


Зачем перемещать бизнес-логику на уровень приложений?

Раньше наши клиенты использовали хранимые процедуры для своей бизнес-логики, думая, что это повысит производительность. Но давайте будем честными: язык SQL, возможно, не является оптимальным выбором для размещения бизнес-логики по сравнению с уровнем приложения.

Фактически SQL лишь запрашивает или изменяет данные в базе данных. Здесь многие могут закидать нас тухлыми помидорами, потому что язык SQL хорошо выполняет сложные соединения, фильтрацию и сортировку, чтобы получить из запроса именно те данные, и не более того. Тогда зачем что-то менять и выносить бизнес-логику на уровень приложения?

Вопрос кажется логичным. Давайте ответим на него подробнее. Ниже мы обозначили 4 основные причины, по которым стоит серьезно задуматься о переносе бизнес-логики в приложение. Решение клиента перенести бизнес-логику на уровень приложения было вызвано следующими причинами:

Масштабируемость

Для масштабируемости лучшим вариантом является хранение бизнес-логики на уровне приложения. Почему? Потому что, как правило, значительно проще масштабировать ресурсы сервера приложений, чем ресурсы сервера базы данных. Это признано почти повсеместно. Для большинства веб-приложений добавление дополнительных серверов обычно не составляет труда, если требуется обрабатывать большой трафик. Однако ценность дополнительных серверов приложений снижается, если ваша база данных не может масштабироваться для удовлетворения возросшего спроса. Масштабирование сервера базы данных значительно сложнее, чем простое добавление серверов приложений.

Ремонтопригодность

Хранение бизнес-логики в базе данных может создать проблемы с удобством обслуживания. Изменение хранимых процедур может нарушить работу многих приложений, ограничить расширяемость и затруднить соблюдение принципа «Не повторяйся» (DRY). Код SQL, превышающий 100 строк, часто создает сложности и трудности с устранением неполадок. Разделение бизнес-логики на уровень приложений может облегчить вход новых членов команды и предоставить более интуитивно понятную платформу для рефакторинга.

Простота разработки

SQL — плохой выбор для кодирования бизнес-правил вашей системы. Он негибкий, и мы не можем полагаться на него при представлении сложных моделей, поскольку он не может создавать правильные абстракции. Это ограничение является основной причиной, по которой следует избегать его использования в бизнес-логике. Речь идет не об инструментах или поддержке, а о неспособности SQL создать простую и выразительную модель предметной области, в отличие от объектно-ориентированного и функционального проектирования, которое предлагает больше возможностей.

Многоразовое использование

В разработке программного обеспечения повторное использование кода — это эффективный способ сэкономить время и деньги при адаптации существующего кода для новых задач. Объектно-ориентированное программирование (ООП) — это метод, который облегчает переработку кода, что делает его пригодным для различных приложений. Однако SQL, обычно используемый в базах данных, предлагает ограниченную гибкость для повторного использования кода. Варианты включают использование «представлений» и «хранимых процедур», хотя последнее может привести к обилию параметров. Чтобы сделать правильный выбор для вашего проекта, необходимо тщательно изучить каждый метод.


Преобразование Transact-SQL в Java

Преобразование Transact-SQL в Java требует ряда важных соображений. Этот процесс включает в себя сопоставление типов данных SQL с их эквивалентами в Java, что обеспечивает точное представление данных. Он также включает в себя перевод SQL-запросов в код Java, где Java использует такие библиотеки, как JDBC или Hibernate, для обработки взаимодействия с базой данных. Более того, некоторые функции ESQL не имеют прямых эквивалентов в Java, что может создать впечатление, что автоматическое преобразование неэффективно.

На этапе настройки нашего проекта мы смогли создать ряд конверсионных решений, которые повысили уровень автоматизации. Эти решения, которые первоначально считались невозможными для автоматизации, в конечном итоге оказались успешными. Давайте углубимся в детали некоторых из них.


  1. Преобразование инструкции INSERT в сочетании с SCOPE_IDENTITY() для получения последнего значения идентификатора, вставленного в столбец идентификаторов.

    Источник:

 ALTER PROCEDURE example1 AS BEGIN Declare @idBit int Declare @c int Insert Into tab (c) Values (@c) Set @idBit = SCOPE_IDENTITY() End


Цель:

 @Service public class Example1 implements IExample1 { @Autowired private JdbcTemplate jdbcTemplate; private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Example1.class); @Override public Integer spExample1() throws SQLException, Exception { Integer mStatus = 0; KeyHolder keyHolder = new GeneratedKeyHolder(); try { Integer idBit = null; Integer c = null; { final Integer tmpC = c; jdbcTemplate.update(connection-> { PreparedStatement ps = connection.prepareStatement("Insert Into tab(c) \r\n" + " Values(?)", new String[] { "" }); ps.setInt( 1, tmpC); return ps; }, keyHolder); } idBit = Tsqlutils.<Integer > strToNum(keyHolder.getKey().toString(), Integer.class); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } } }
  1. Преобразование процедуры с несколькими наборами результатов.

Источник:

 ALTER PROCEDURE [returnSeveralResultSet] @p1 int, @p2 varchar(50) AS Begin select cob_ft, lower(buzon) from tab1 where cob_id = @p1 and cob_ft = @p2 select dep_ft, lower(fiton) from tab2 END


Цель:

 @Service public class Returnseveralresultset implements IReturnseveralresultset { @Autowired private JdbcTemplate jdbcTemplate; private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Returnseveralresultset.class); private Integer errorCode = 0; private String sqlState = ""; @Override public Map<String, Object> spReturnseveralresultset(Integer p1, String p2) throws Exception { Integer mStatus = 0; Map<String, Object> outData = new HashMap<>(); List<SqlRowSet> outRsList = new ArrayList<>(); SqlRowSet rowSet; try { rowSet = jdbcTemplate.queryForRowSet("select cob_ft, lower(buzon) from tab1 \r\n" + " where cob_id = ? and cob_ft = ?", p1, p2); outRsList.add(rowSet); rowSet = jdbcTemplate.queryForRowSet("select dep_ft, lower(fiton) from tab2"); outRsList.add(rowSet); return outData; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return outData; } finally { outData.put("status", mStatus); outData.put("rsList", outRsList); } } }
  1. Преобразование метода DATEDIFF. Поскольку в Java нет прямых эквивалентов, команда Ispirer разработала эквивалент этого метода, который преобразует строку в Timestamp без явно заданного формата. Это делает результат кода лаконичным и его легче читать. Пример ниже демонстрирует, как он используется.

Источник:

 create procedure datediffFn as declare @var1 int set @var1 = DATEDIFF(dd, '1999-01-01', '2000-02-01') set @var1 = DATEDIFF(mm, getdate(), '2000-02-01') set @var1 = DATEDIFF(week, '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000');


Цель:

 public Integer spDatedifffn() throws Exception { Integer mStatus = 0; try { Integer var1 = null; var1 = Tsqlutils.datediff("dd", Tsqlutils.toTimestamp("1999-01-01"), Tsqlutils.toTimestamp("2000-02-01")); var1 = Tsqlutils.datediff("mm", new Timestamp(new java.util.Date().getTime()), Tsqlutils.toTimestamp("2000-02-01")); var1 = Tsqlutils.datediff("week", Tsqlutils.toTimestamp("2005-12-31 23:59:59.9999999"), Tsqlutils.toTimestamp("2006-01-01 00:00:00.0000000")); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } }
  1. Преобразование метода sp_send_dbmail, который отправляет сообщение электронной почты указанным получателям. Для этой цели был разработан класс MailService. Этот метод позволяет отправлять электронные письма с подробными характеристиками, включая получателей (TO), получателей копии (CC), получателей в скрытой копии (BCC), тему письма, основной текст, вложения и многое другое. . Чтобы не загромождать основной код, наша команда поместила метод в отдельный класс.

Источник:

 create PROCEDURE spSendDbmail AS BEGIN EXEC msdb.dbo.sp_send_dbmail @profile_name = 'New DB Ispirer Profile', @recipients = '[email protected]', @body = '<h1>This is actual message embedded in HTML tags</h1>', @subject = 'Automated Success Message' , @file_attachments = 'C:\Temp\Attached.txt', @body_format='HTML', @copy_recipients = '[email protected]', @blind_copy_recipients = '[email protected]'; END


Цель:

 import java.util.*; import com.ispirer.mssql.mail.MailService; public class Spsenddbmail { private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Spsenddbmail.class); public Integer spSpsenddbmail() throws Exception { Integer mStatus = 0; try { MailService.send("New DB Ispirer Profile", "Automated Success Message", "<h1>This is actual message embedded in HTML tags</h1>", "[email protected]", "[email protected]", "[email protected]", "C:\\Temp\\Attached.txt", "HTML"); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } } }


  1. Команда Ispirer разработала класс XMLUtils для преобразования типа данных xml и его методы, которые используются для получения любой информации из данных XML, хранящихся в переменной XML. Пример реализации метода:

Источник:

 create procedure workWithXml AS begin declare @result bit, @myDoc XML, @myStr varchar(1000), @ProdID INT SET @myDoc = '<Root> <ProductDescription ProductID="1" ProductName="Road Bike"> <Features> <Warranty>1 year parts and labor</Warranty> <Maintenance>3 year parts and labor extended maintenance is available</Maintenance> </Features> </ProductDescription> </Root>' SET @result = @myDoc.exist('(/Root/ProductDescription/@ProductID)[1]') SET @myStr = cast(@myDoc.query('/Root/ProductDescription/Features') as varchar(max)) SET @ProdID = @myDoc.value('(/Root/ProductDescription/@ProductID)[1]', 'int' ) end;


Цель:

 import java.util.*; import com.ispirer.mssql.xml.XMLUtils; public class Workwithxml { private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Workwithxml.class); public Integer spWorkwithxml() throws Exception { Integer mStatus = 0; try { Boolean result = null; String myDoc = null; String myStr = null; Integer prodID = null; myDoc = "<Root> " + "<ProductDescription ProductID=\"1\" ProductName=\"Road Bike\"> " + "<Features> " + "<Warranty>1 year parts and labor</Warranty> " + "<Maintenance>3 year parts and labor extended maintenance is available</Maintenance> " + "</Features> " + "</ProductDescription> " + " </Root>"; result = XMLUtils.exist(myDoc, "(/Root/ProductDescription/@ProductID)[1]"); myStr = XMLUtils.query(myDoc, "/Root/ProductDescription/Features"); prodID = XMLUtils.<Integer > value(myDoc, "(/Root/ProductDescription/@ProductID)[1]", Integer.class); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } } }


Благодаря нашим усилиям по настройке наша команда успешно разработала ряд методов для автоматизации перехода с T-SQL на Java. Это значительно сократило общее время миграции для всего проекта, что позволило нам ускорить миграцию в 4 раза по сравнению с потенциальной миграцией вручную. Настройка нашего набора инструментов не только ускорила переход, но и повысила общую эффективность проекта, продемонстрировав ценное влияние наших инициатив по настройке. Указанные в примерах методы предоставляются клиенту вместе с результатами преобразования.


Заключение

В заключение отметим, что переход бизнес-логики с Transact-SQL на Java — это многогранный процесс, требующий всестороннего понимания обоих языков и их особенностей.


В этой статье мы подробно изучили миграцию бизнес-логики на уровень приложения и предоставили ценную информацию для тех, кто планирует такой переход. Случай нашего клиента доказывает, что подобные проекты модернизации можно автоматизировать, что существенно экономит время и силы при миграции. Проект нашего клиента служит убедительным свидетельством замечательного потенциала автоматизации. Это демонстрирует, что существуют аспекты модернизации, в которых автоматизация может успешно оптимизировать процессы, которые изначально могут оказаться за пределами ее возможностей.


В конечном счете, переход с Transact-SQL на Java — это стратегический шаг для организаций, стремящихся к большей гибкости, кросс-платформенной совместимости и масштабируемости. Несмотря на то, что он представляет собой ряд проблем, преимущества с точки зрения переносимости, производительности и адаптации к современным программным архитектурам делают этот переход стоящим усилием для тех, кто хочет модернизировать свои системы баз данных и приложения.