Примечание Кураторское: Это последняя статья в серии из трех статей , исследующих NuoDB. Вы можете узнать больше о NuoDB, а также получить бесплатную пробную версию, перейдя на сайт NuoDB .
Вступление
В предыдущих статьях мы показали архитектуру NuoDB NewSQL, ее ключевые компоненты и способы ее легкого масштабирования на уровнях транзакций и хранения. Мы также продемонстрировали JDBC и Hibernate с NuoDB. В этом заключительном посте из серии из 3 статей мы продемонстрируем Spring и Hibernate с NuoDB в облачном масштабе с использованием возможностей AWS (AWS EC2 и CloudFormation).
Весна и зимняя спячка с NuoDB
Spring PetClinic — это пример приложения, которое распространяется вместе с Spring Framework. Он предназначен для того, чтобы показать, как можно использовать среды приложений Spring для создания простых, но мощных приложений, ориентированных на базы данных. В этом году он был реорганизован с учетом новой архитектуры, и исходный код можно загрузить с Github . Spring PetClinic изначально поддерживает базы данных HSQL и MySQL, и в этом посте мы портируем его для использования с NuoDB.
Чтобы получить код, нам нужно запустить:
$ git clone https://github.com/SpringSource/spring-petclinic.git
Приложение может быть построено и запущено с помощью команды maven, но сначала нам нужно реализовать изменения, связанные с NuoDB, которые связаны с настройкой базы данных, обновлением конфигураций Hibernate и Spring. Другими словами, ни один источник приложения не нуждается в модификации.
Сценарии для слоя db можно найти в этом каталоге:
~ / spring / spring-petclinic / src / main / resources / db . Там мы создали новый
каталог NuoDB и создали два сценария SQL: initDB.sql и populateDB.sql.
$ cd ~/spring/spring-petclinic/src/main/resources/db $ mkdir nuodb $ vi initDB.sql # edit initDB.sql DROP TABLE vet_specialties IF EXISTS; DROP TABLE vets IF EXISTS; DROP TABLE specialties IF EXISTS; DROP TABLE visits IF EXISTS; DROP TABLE pets IF EXISTS; DROP TABLE types IF EXISTS; DROP TABLE owners IF EXISTS; CREATE TABLE vets ( id INTEGER primary key generated always as identity, first_name VARCHAR(30), last_name VARCHAR(30) ); CREATE INDEX vets_last_name ON vets (last_name); CREATE TABLE specialties ( id INTEGER primary key generated always as identity, name VARCHAR(80) ); CREATE INDEX specialties_name ON specialties (name); CREATE TABLE vet_specialties ( vet_id INTEGER NOT NULL, specialty_id INTEGER NOT NULL ); ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets (id); ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id); CREATE TABLE types ( id INTEGER primary key generated always as identity, name VARCHAR(80) ); CREATE INDEX types_name ON types (name); CREATE TABLE owners ( id INTEGER primary key generated always as identity, first_name VARCHAR(30), last_name VARCHAR(30), address VARCHAR(255), city VARCHAR(80), telephone VARCHAR(20) ); CREATE INDEX owners_last_name ON owners (last_name); CREATE TABLE pets ( id INTEGER primary key generated always as identity, name VARCHAR(30), birth_date DATE, type_id INTEGER NOT NULL, owner_id INTEGER NOT NULL ); ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id); ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id); CREATE INDEX pets_name ON pets (name); CREATE TABLE visits ( id INTEGER primary key generated always as identity, pet_id INTEGER NOT NULL, visit_date DATE, description VARCHAR(255) ); ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); CREATE INDEX visits_pet_id ON visits (pet_id); $ vi populateDB.qsl # edit populateDB.sql INSERT INTO vets VALUES (NULL, 'James', 'Carter'); INSERT INTO vets VALUES (NULL, 'Helen', 'Leary'); INSERT INTO vets VALUES (NULL, 'Linda', 'Douglas'); INSERT INTO vets VALUES (NULL, 'Rafael', 'Ortega'); INSERT INTO vets VALUES (NULL, 'Henry', 'Stevens'); INSERT INTO vets VALUES (NULL, 'Sharon', 'Jenkins'); INSERT INTO specialties VALUES (NULL, 'radiology'); INSERT INTO specialties VALUES (NULL, 'surgery'); INSERT INTO specialties VALUES (NULL, 'dentistry'); INSERT INTO vet_specialties VALUES (2, 1); INSERT INTO vet_specialties VALUES (3, 2); INSERT INTO vet_specialties VALUES (3, 3); INSERT INTO vet_specialties VALUES (4, 2); INSERT INTO vet_specialties VALUES (5, 1); INSERT INTO types VALUES (NULL, 'cat'); INSERT INTO types VALUES (NULL, 'dog'); INSERT INTO types VALUES (NULL, 'lizard'); INSERT INTO types VALUES (NULL, 'snake'); INSERT INTO types VALUES (NULL, 'bird'); INSERT INTO types VALUES (NULL, 'hamster'); INSERT INTO owners VALUES (NULL, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); INSERT INTO owners VALUES (NULL, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); INSERT INTO owners VALUES (NULL, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); INSERT INTO owners VALUES (NULL, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); INSERT INTO owners VALUES (NULL, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); INSERT INTO owners VALUES (NULL, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); INSERT INTO owners VALUES (NULL, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); INSERT INTO owners VALUES (NULL, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); INSERT INTO owners VALUES (NULL, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); INSERT INTO owners VALUES (NULL, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); INSERT INTO pets VALUES (NULL, 'Leo', '2010-09-07', 1, 1); INSERT INTO pets VALUES (NULL, 'Basil', '2012-08-06', 6, 2); INSERT INTO pets VALUES (NULL, 'Rosy', '2011-04-17', 2, 3); INSERT INTO pets VALUES (NULL, 'Jewel', '2010-03-07', 2, 3); INSERT INTO pets VALUES (NULL, 'Iggy', '2010-11-30', 3, 4); INSERT INTO pets VALUES (NULL, 'George', '2010-01-20', 4, 5); INSERT INTO pets VALUES (NULL, 'Samantha', '2012-09-04', 1, 6); INSERT INTO pets VALUES (NULL, 'Max', '2012-09-04', 1, 6); INSERT INTO pets VALUES (NULL, 'Lucky', '2011-08-06', 5, 7); INSERT INTO pets VALUES (NULL, 'Mulligan', '2007-02-24', 2, 8); INSERT INTO pets VALUES (NULL, 'Freddy', '2010-03-09', 5, 9); INSERT INTO pets VALUES (NULL, 'Lucky', '2010-06-24', 2, 10); INSERT INTO pets VALUES (NULL, 'Sly', '2012-06-08', 1, 10); INSERT INTO visits VALUES (NULL, 7, '2013-01-01', 'rabies shot'); INSERT INTO visits VALUES (NULL, 8, '2013-01-02', 'rabies shot'); INSERT INTO visits VALUES (NULL, 8, '2013-01-03', 'neutered'); INSERT INTO visits VALUES (NULL, 7, '2013-01-04', 'spayed');
Затем нам пришлось изменить файл business-config.xml в
каталоге ~ / spring / spring-petclinic / src / main / resources / spring, чтобы он ссылался на правильный NuoDB hibernate.dialect с помощью свойства hibernate.dialect:
# business-config.xml <!-- JPA EntityManagerFactory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource"> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> <property name="jpaPropertyMap"> <map> <entry key="hibernate.show_sql" value="${jpa.showSql}" /> <entry key="hibernate.dialect" value="${hibernate.dialect}" /> <entry key="hibernate.temp.use_jdbc_metadata_defaults" value="false" /> </map> </property> <!-- gDickens: BOTH Persistence Unit and Packages to Scan are NOT compatible, persistenceUnit will win --> <property name="persistenceUnitName" value="petclinic"/> <property name="packagesToScan" value="org.springframework.samples.petclinic"/> </bean>
Чтобы поддерживать Hibernate 4, мы также устанавливаем hibernate.temp.use_jdbc_metadata_defaults в false.
Свойства базы данных должны быть настроены в файле data-access.properties — этот файл содержит соответствующие параметры JDBC (используемые в data-source.xml), а также диалект Hibernate. В приведенном ниже примере есть ссылка на локальный
экземпляр NuoDB, работающий на виртуальной машине Ubuntu, и экземпляр AWS EC2 (закомментированный), который будет настроен позже в этой статье:
jdbc.driverClassName=com.nuodb.jdbc.Driver jdbc.url=jdbc:com.nuodb://192.168.80.128/spring?schema=user #jdbc.url=jdbc:com.nuodb://ec2-46-51-162-14.eu-west-1.compute.amazonaws.com/spring?schema=user jdbc.username=spring jdbc.password=spring # Properties that control the population of schema and data for a new data source jdbc.initLocation=classpath:db/nuodb/initDB.sql jdbc.dataLocation=classpath:db/nuodb/populateDB.sql # Property that determines which Hibernate dialect to use # (only applied with "applicationContext-hibernate.xml") hibernate.dialect=com.nuodb.hibernate.NuoDBDialect # Property that determines which database to use with an AbstractJpaVendorAdapter jpa.showSql=true
Файл datasource-config.xml определяет компонент источника данных с использованием JDBC:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/>
Оригинальный pom.xml от Github ссылается на Hibernate 4, а NuoDB может поддерживать Hibernate 4, поэтому мой pom.xml выглядел так:
# pom.xml <properties> <!-- Hibernate / JPA --> <hibernate.version> 4.1.0.Final</hibernate.version> <!-- Bean validation --> <hibernate-validator.version> 4.2.0.Final</hibernate-validator.version> <nuodb.version>1.1</nuodb.version> </properties> <dependencies> <!-- For NuoDB --> <dependency> <groupId>com.nuodb</groupId> <artifactId>nuodb-hibernate</artifactId> <version>${nuodb.version}</version> </dependency> <dependency> <groupId>com.nuodb</groupId> <artifactId>nuodb-jdbc</artifactId> <version>${nuodb.version}</version> </dependency> </dependencies>
Наконец, нам нужно изменить файл web.xml в каталоге ~ / spring / spring-petclinic / src / main / webapp / WEB-INF, чтобы использовать jpa — стандартная конфигурация использует jdbc.
<context-param> <param-name>spring.profiles.active</param-name> <param-value>jpa</param-value> </context-param>
Теперь мы можем запустить команду maven, чтобы скомпилировать код, инициализировать и заполнить таблицы NuoDB, а затем прослушать порт 9966 для запросов.
$ mvn tomcat7:run
Также мы можем подключить Spring, используя http: // localhost: 9966 / petclinic / .
Spring PetClinic с использованием NuoDB на AWS
До сих пор мы использовали локальный экземпляр NuoDB. Теперь пришло время перенести слой базы данных в облако AWS. Чтобы запустить NuoDB на экземплярах AWS EC2, одним из самых простых вариантов является использование AWS CloudFormation. На github доступны шаблоны CloudFormation .
Чтобы скачать их, мы можем запустить
$ git clone https://github.com/nuodb/cloudformation.git
Затем нам нужно открыть консоль управления AWS; перейдите в CloudFormation и выберите «Создать стек» и загрузите шаблон NuoDB. (например, NuoDB-1.1. шаблон в нашем случае). Затем мы можем определить количество агентов (в дополнение к брокеру), имя домена, имя пользователя и пароль администратора домена и тип экземпляра EC2.
Нажмите на все изображения для увеличения
Как только мы нажмем продолжить, будут созданы экземпляры EC2. Сначала статус будет CREATE_IN_PROGRESS, затем CREATE_COMPLETE.
В результате мы получим 3 экземпляра EC2 (так как мы выбрали 2 агентов); один предназначен для брокера NuoDB, а два других — для агентов NuoDB. У нас также будет 3 тома EBS, по одному для каждого экземпляра EC2.
ВНИМАНИЕ .
Скрипт NuoDB CloudFormation использует группу автоматического масштабирования EC2, которая гарантирует, что число выбранных вами агентов всегда будет работать. В результате, если вы просто остановите экземпляры EC2 в конце теста, AWS перезапустит их. Чтобы все правильно остановить и очистить тестовую среду, откройте консоль управления AWS, перейдите в CloudFormation, выберите стек NuoDB и нажмите «Удалить стек». Это завершит все экземпляры, которые были запущены шаблоном CloudFormation. Подробнее об автоматическом масштабировании AWS и о том, как использовать инструмент командной строки, можно узнать на веб-сайте AWS .
Теперь мы можем подключиться к хосту EC2, на котором работает брокер NuoDB:
После входа в систему мы можем запустить базу данных:
На следующих шагах мы можем определить имя базы данных (весна), оставив невыбранной опцию «разрешить недолговечную базу данных» и каталоги архива и журнала для менеджера хранилища, работающего на одном из хостов ( / home / ec2-user / nuodb) / data и / home / ec2-user / nuodb / journal соответственно). Обратите внимание, что каталог / home / ec2-user должен иметь соответствующие права, чтобы разрешить создание каталога данных и журнала (например, -rwxrwxrwx в нашем тесте).
После этого мы можем определить механизм транзакций, работающий на другом хосте EC2:
Теперь у нас есть 3 хоста EC2: один для брокера NuoDB для обслуживания клиентских подключений, один для менеджера хранилища с файловой системой и один для механизма транзакций.
Теперь, если мы изменим строку подключения jdbc в Spring PetClinic (помните, она определена в data-access.properties), мы можем подключить наше приложение к
NuoDB с помощью серверов AWS. Причина, по которой соединение возможно, заключается в том, что группы безопасности AWS позволяют подключать любые серверы.
$ vi data-access.properties #jdbc.url=jdbc:com.nuodb://192.168.80.128/spring?schema=user jdbc.url=jdbc:com.nuodb://ec2-46-51-162-14.eu-west-1.compute.amazonaws.com/spring?schema=user
Затем мы можем повторно запустить команду Spring PetClinic — на этот раз с базой данных в облаке AWS:
$ mvn tomcat7:run
Когда сервер Tomcat запущен и работает, мы можем перейти по адресу http://ec2-46-51-162-14.eu-west-1.compute.amazonaws.com:9966/petclinic/ и мы можем искать можно добавлять новых владельцев, мы можем их искать и т. д.
Масштабирование и устойчивость
Масштабирование — это метод добавления вычислительных ресурсов путем добавления дополнительных компьютеров в систему, а не увеличения вычислительных ресурсов на компьютерах в системе. Устойчивость — это способность обеспечивать и поддерживать приемлемый уровень обслуживания в случае неисправностей.
Если мы хотим масштабировать нашу базу данных, а также сделать ее эластичной, мы можем просто вернуться к консоли NuoDB и добавить новый процесс с помощью меню «Добавить процесс». Например, мы можем добавить механизм транзакций на сервер EC2, на котором изначально работал менеджер хранилища, и мы также можем добавить менеджер хранилища на сервер EC2, на котором ранее работал сервер транзакций. Таким образом, у нас есть два сервера EC2, на которых запущен один экземпляр механизма транзакций и менеджер хранилища.
Масштабирование базы данных — это простой процесс для приложения Spring PetClinic; мы просто запускаем другой сервер EC2 с агентом и добавляем механизм транзакций или механизм хранения. На Youtube загружен вебинар, в котором рассказывается, как масштабировать NuoDB на AWS всего несколькими щелчками мыши.
Как видно из
отчета о производительности NuoDB, NuoDB масштабируется почти линейно. На диаграмме ниже показано, как можно увеличить количество транзакций в секунду (TPS), добавив новый узел:
Вывод
Как мы видели в этой серии,
NuoDB объединяет стандартные свойства SQL и ACID с эластичной масштабируемостью, что делает его идеально подходящим для использования в качестве надежной облачной системы управления данными. Его уникальный архитектурный подход обеспечивает высокую производительность операций чтения и записи и геораспределения операций 24/7 со встроенной отказоустойчивостью. Более того, приложения, использующие известные платформы, такие как Spring и Hibernate, могут быть легко перенесены или разработаны с помощью NuoDB в качестве базы данных NewSQL, отвечающей требованиям облачного масштаба.