Sequoia изнутри #1

Август 27th, 2009 по SadKo Оставить ответ »

Как бэ вступление

По работе возникла необходимость синхронной рабты с кластером БД (4 базы, в которых должны храниться одни и те же данные). Для этого я несколько месяцев подряд писать тулзу data_proc (коммерческая разработка), которая обрабатывает данные в поточном режиме и устойчива к connection-loss/database-failure ошибкам. Единственный недостаток — это хранение данных на локальном диске в виде журналов, объём которых достаточно велик, если база несколько часов находится offline.
Помимо data_proc у нас есть ещё куча других приложений, для которых пришлось писать балансировщик нагрузки для SELECT-запросов, с чем мы успешно справились. Тем не менее, вопрос балансировки нагрузки и кластеризации (с целью упрощения data_proc) остался, и мне предложили разобраться с C-JDBC, о чём я и буду сейчас писать.

C-JDBC или Sequoia

Собственно, было предложено покопаться в проекте C-JDBC (Clustered JDBC), который имеет лицензию LGPL. Выкачал дистрибутив, сорсы и доки для Linux, поставил в /opt. Стал разбираться, как скрестить это чудо с ORACLE. Честно прочитал бОльшую часть документации на этот продукт, и после некоторых бдений с когфигами и осознавания того, что я делаю не так, выяснил, что ан-нет, не получается никак. Это чудо генерило исключения при попытке получить схему БД ORACLE. Да, я бы всё понял, если бы это не было java.lang.NullPointerException. После долгих скитаний в Google я, было, совсем отчаялся.
«А, может, я не ту версию скачал?» — подумал я, и пошёл снова на официальный сайт C-JDBC, на котором заметил, что C-JDBC имеет своё продолжение — проект Sequoia, с изменённой лицензией на Apache License. Скачав последнюю версию, стал ковырять…

Первые грабли

Первыми граблями оказалось портирование конфига с C-JDBC на Sequoia. Очень жестокий XML-валидатор ругался и матерился, пока я всё-таки не выяснил, что ему действительно было нужно от меня. Разобравшись с валидатором, я всё-таки написал конфиг, объединяющий две схемы двух разных БД в кластер по технологии RAIDb-1. Контроллер вроде бы запустился, да даже вроде бы поднял так называемые backends (проще говоря, законнектился к базам).
Отлично, теперь можно слабать простенькую табличку:
CREATE TABLE TM_FIRST
(
nID NUMBER,
strMessage VARCHAR2(256),
nCode NUMBER
)

Что я незамедлительно и проделал на обеих схемах.
Пришло время написать какой-нить код, который что-то делает с этим кластером. Что ж, берём в руки Eclipse, создаём проект и заводим вот такой классик:

package test.cjdbc;

import java.sql.*;

import org.continuent.sequoia.driver.DataSource;


/** CJDBC controller test
 * @author Vladimir Sadovnikov
 *
 */

public class Tm_CJDBCTest
{
	/**
	 * @param args
	 */
	public static void main(String[] args)

	{
		DataSource ds = new DataSource();
		
		ds.setURL("jdbc:sequoia://localhost:25322/CJDBC");

		ds.setUser("user");
		ds.setPassword("userpass");

		
		try
		{
			Connection conn = ds.getConnection();

			conn.setAutoCommit(false);
			
			try
			{	
				PreparedStatement stm = conn.prepareStatement("INSERT INTO Tm_First (nID, strMessage, nCode) VALUES (?, ?, ?)");

				try
				{
					stm.setInt(1, 666);

					stm.setString(2, "Hello, World!");
					stm.setInt(3, 13);

					stm.addBatch();
					
					stm.execute();
					conn.commit();

				}
				catch (SQLException ex)
				{
					conn.rollback();

					throw ex;
				}
				finally
				{
					stm.close();

				}
				
				stm = conn.prepareStatement("SELECT * from Tm_First");
				
				try

				{
					ResultSet rset = stm.executeQuery();
					
					try

					{
						while (rset.next())
						{

							String result = "fetched item: ";
							result += rset.getInt(1) + ";";

							result += rset.getString(2) + ";";

							result += rset.getInt(3) + "\n";

							System.out.println(result);
						}
					}

					finally
					{
						rset.close();
					}

				}
				catch (SQLException ex)
				{
					conn.rollback();

					throw ex;
				}
				finally
				{
					stm.close();

				}
			}
			finally
			{
				conn.close();

			}
		}
		catch (SQLException ex)
		{
			ex.printStackTrace();

		}
	}
}

Запускаем класс на выполнение, в базы вставляется по строчке, контроллер рапортует об успехе, выдав мне на SELECT-запрос строчку. Ура-ура-ура: в базах данные вроде бы синхронны. Что ж, пора брать в руки молоток.

Краш-тест

Что ж, посмотрим, как контроллер отреагирует на отказ в работе одной из БД.
Для этого, не мудрствуя лукаво, я делаю следующий трюк:
ALTER USER cjdbc ACCOUNT LOCK
То есть, блокирую аккаунт, через который контроллер Sequoia подключается к базе. После чего вывожу список коннекций:
select s.sid s.serial#, s.osuser, s.username, s.program FROM v$session s where USERNAME like 'CJDBC' and OSUSER IS NULL
И поочереди сношу их через
ALTER SYSTEM KILL SESSION IMMEDIATE;
После этого база контроллеру недоступна, и я с чистой совестью снова прогоняю тест. В результате чего в одной базе две записи, в другой — одна. И никаких дополнительных метаданных, по которым можно было бы восстановить зеркальность баз, нет ни в первой, ни во второй.
Что ж, может это очень умная штука, которая использует какие-то ораклёвые фичи, о которых я не знаю? OK, тогда разрешаем аккаунт:
ALTER USER cjdbc ACCOUNT UNLOCK
И снова прогоняем тест. В первой базе три записи, во второй — по-прежнему одна, а SELECT бодро выдаёт три записи через ResultSet.
Может быть, оно после рестарта как-то восстановится? Ладно, вырубаю контроллер (жёстко, по ctrl-c). Запускаю снова. Sequoia подключается к обеим базам, вытаскивает схемы и… больше ничего не делает.
Ладно, прогоняю ещё раз тест… В первой базе четыре записи, во второй — всего две, и выдёргивается через SELECT только две.

Но не может же быть!

subj, ведь в официальной документации от Sequoia говорится следующее:

You have a Java application or a Java-based application server that accesses one or several databases. The database tier becomes the bottleneck of your application or it is a single point of failure or both. Sequoia can help you resolve these problems by providing:
* performance scalability by adding database nodes and balancing the load among these nodes.
* high availability of the database tier, i.e. Sequoia tolerates database crashes and offers transparent failover using database replication techniques.
* improved performance with fine grain query caching and transparent connection pooling.
* SQL traffic logging for performance monitoring and analysis.
* support for clusters of heterogeneous database engines.

Вспоминаю, что в доках упоминалась такая фигня, как RecoveryLog. Может, причина в том, что я не сконфигурировал его? Да, похоже, надо конфигурить, но это тема для отдельного поста.

Заключение

Первое знакомство с C-JDBC оказалось неудачным, в Sequoia был пофиксен ряд багов, что, тем не менее, не мешало ей валить исключения при определённых настройках. Тестирование работы RAIDb-1 оказалось полностью провальным (до первого сбоя), опция RecoveryLog не использовалась. Похоже, что в документации нас хотят обмануть. Но исследование продолжается.

Реклама

Добавить комментарий

Blue Captcha Image
Refresh

*