Tag Archives: bases de datos

Exportar base de datos SQL SERVER a un BLOB en Azure como backup

Decir que Azure, la plataforma Cloud de Microsoft, es una de las más potentes del mercado pese a su corto tiempo de vida no es algo nuevo aunque, precisamente por su juventud, nos encontramos con algunas carencias que hacen algo más complicado las gestiones típicas de un sistema en producción.

Una de estas carencias es la posibilidad de automatizar backups (copias de seguridad) de nuestras bases de datos SQL SERVER algo que necesitamos tener cuando nuestro proyecto pasa el estado de desarrollo.

 

La única posibilidad que nos ofrece Azure en este momento (25/06/2013) es exportar/importar nuestras bases de datos a un blob desde el panel de control a petición pero no podemos programar esta tarea para que se ejecute periódicamente.

 

Esta opción genera en uno de nuestros containers un blob con extensión .bacpac con la copia de seguridad de la base de datos escogida para poder importarla en cualquier momento.

La pregunta es, ¿cómo podemos hacer esto automáticamente? La respuesta, con una aplicación que llame periódicamente a la misma API REST que usa Azure para estas tareas.

 

Azure Sql Server API REST

Azure Sql Server expone un API REST con algunas tareas básicas que podemos invocar (con las debidas credenciales, claro está) para exportar o importar nuestras bases de datos contra Azure Storage.

Cada una de las regiones de Azure Sql Server tiene su propia url del servicio por lo que deberás asegurarte de usar la url correcta en función de en que región se encuentre tu base de datos:

 

 

DataCenter Endpoint
North Central US https://ch1prod-dacsvc.azure.com/DACWebService.svc/
South Central US https://sn1prod-dacsvc.azure.com/DACWebService.svc/
North Europe https://db3prod-dacsvc.azure.com/DACWebService.svc/
West Europe https://am1prod-dacsvc.azure.com/DACWebService.svc/
East Asia https://hkgprod-dacsvc.azure.com/DACWebService.svc/
Southeast Asia https://sg1prod-dacsvc.azure.com/DACWebService.svc/
East US https://bl2prod-dacsvc.azure.com/DACWebService.svc/
West US https://by1prod-dacsvc.azure.com/DACWebService.svc/

 

Las dos tareas expuestas por este servicio son “Export” e “Import” (para exportar e importar respectivamente) por lo que, por ejemplo, para solicitar una exportación de una base de datos alojada en el Norte de Europa deberíamos hacer un POST contra la url: https://db3prod-dacsvc.azure.com/DACWebService.svc/Export

 

Solicitando Exportación desde código

Para automatizar el proceso de exportación podemos programar un pequeño Worker Role de Azure, un servicio de Windows que se ejecute en uno de nuestros servidores locales o incluso que lo implemente nuestra propia web de administración. En mi caso dispongo de un Worker Role propio con varias tareas de mantenimiento que se ejecutan cada cierto tiempo por lo que me fue muy fácil incluir una nueva tarea para hacer este backup.

Para hacer esta exportación, como hemos comentados antes, basta con hacer un POST contra la [url del servicio] + “/Export” incluyendo en el cuerpo de la petición un xml con los datos necesarios para la tarea.

 

Este xml que tenemos que postear tiene el siguiente formato:

[code language=”xml”]

<ExportInput
xmlns="http://schemas.datacontract.org/2004/07/Microsoft.SqlServer.Management.Dac.ServiceTypes"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<BlobCredentials
i:type="BlobStorageAccessKeyCredentials">
<Uri>[URL del Blob a crear]</Uri>
<StorageAccessKey>[Clave de acceso del Azure Storage]</StorageAccessKey>
</BlobCredentials>
<ConnectionInfo>
<DatabaseName>[Nombre de la base de datos a exportar]</DatabaseName>
<Password>[Password del usuario de la base de datos]</Password>
<ServerName>[Nombre del servidor en el que se encuentra la base de datos]</ServerName>
<UserName>[Usuario de acceso a la base de datos]</UserName>
</ConnectionInfo>
</ExportInput>

[/code]

Los parámetros que debes rellenar son:

  • [URL del Blob a crear]
    • Url completa del blob que vas a crear con “.bacpac” al final.
      • Ej: https://mistorageenazure.blob.core.windows.net/bak/backup-2013-06-25_09-49.bacpac
  • [Clave de acceso del Azure Storage]
    • La “Primary Access Key” de nuestro Storage en Azure. La podemos encontrar en el panel de administración de Azure > Storage > [el storage al que queremos acceder] > Manage Access Keys
  • [Nombre del servidor en el que se encuentra la base de datos]
    • Nombre completo del servidor de SQL SERVER en el que se encuentra la base de datos a exportar (debe terminar en “database.windows.net”)
      • Ej: server.database.windows.net
  • Datos de la BD
    • Nombre, usuario y contraseña de la base de datos a exportar

 

Con este xml generado ya solo necesitamos hacer un POST contra la url del servicio para solicitar la tarea de exportación.

Este servicio nos devuelve un GUID para la posterior comprobación del estado de la tarea. Podemos guardarlo si queremos para poder saber si ha terminado con éxito o no.

Aquí un ejemplo con el código completo:

[code language=”csharp”]
private Guid RequestExport(string databaseName, string containerUrl, string storageAccessKey, string blobName)
{
// Método que devolvería la URL del Servicio en función de la Región. Yo le paso un tipo enum propio por comodidad
var managementUrl = GetAzureManagementUrlByRegion(AzureRegions.NorthEurope);

var request = WebRequest.Create(managementUrl + "/Export");
request.Method = "POST";

var dataStream = request.GetRequestStream();
// Método que genera el XML que se le pasa como Body con el formato comentado anteriormente
var body = GetExportToBlobBodyRequest(blobUrl, storageAccessKey, databaseName);
var utf8 = new UTF8Encoding();
var buffer = utf8.GetBytes(body);
dataStream.Write(buffer, 0, buffer.Length);

dataStream.Close();
request.ContentType = "application/xml";

// La respuesta HTTP contiene el GUID que representa la tarea serializado como XML
using (var response = request.GetResponse())
{
var encoding = Encoding.GetEncoding(1252);
using (var responseStream = new StreamReader(response.GetResponseStream(), encoding))
{
using (var reader = XmlDictionaryReader.CreateTextReader(responseStream.BaseStream, new XmlDictionaryReaderQuotas()))
{
var serializer = new DataContractSerializer(typeof(Guid));
return (Guid)serializer.ReadObject(reader, true);
}
}
}
}
[/code]

¡Listo! Nuestra tarea de exportación ya se está lanzando y, si todo funciona como debe, en breve se creará un nuevo blob con el contenido de nuestra base de datos para poder importarlo en caso de catástrofe o para replicarlo en otra base de datos distinta para hacer pruebas.

Comprobando el estado de la tarea

Si queremos saber si todo ha ido bien o ha fallado algo podemos hacer GET a otro método del API REST de Azure llamado “Status” indicando el GUID obtenido en la petición de la tarea. Para ello basta con hacer GET de la siguiente url:

[Url del servicio API REST de tu Región]/Status?servername=[servidor de base de datos completo]&username=[usuario de la base de datos]&password=[password de la base de datos]&reqId=[GUID de la tarea]

 

Esta url nos debe devolver un XML con información del estado de la tarea.

 

¡Hecho! Con un simple cliente HTTP podemos hacer exportaciones e importaciones periódicas y automáticas de nuestra base de datos y así protegernos ante cualquier problema que podamos tener.

Como siempre para cualquier duda ya sabéis dónde podéis encontrarme.

 

¡Un saludo y nos vemos Compilando!

Configurar Réplica Maestro – Esclavo en MySql Server

 

Sé que este artículo se aleja un poco de lo que suelo escribir por aquí pero la clase magistral que me ha dado mi gran amigo Pedro Sanz sobre MySql bien se merece una entrada en el blog :-)

 

Hoy hemos tenido que montar para un cliente un servidor de réplica de MySql en el que era imperioso que los datos se espejeran de forma inmediata entre el servidor maestro y el esclavo.

Una réplica de MySql Server hace uso del fichero binario de transacciones para almacenar en el maestro todos los cambios reaizados (UPDATES, DELETES, CREATE, etc..) para que un servidor externo lo lea y replique exactamente los mismos cambios en su propia base de datos.

De este modo tenemos uno o más servidores MySql esclavos haciendo las mismas transacciones que el maestro para así tener los mismos datos en diferentes servidores cosa que se realmente útil y, no sólo ante caídas, ya que es posible configurar nuestra aplicación para compartir las SELECT entre distintos nodos de MySql y mejorar así el rendimiento.

 

Bueno, menos teoría y vamos al lío!.

Lo primero que debemos hacer es configurar el servidor maestro para que almacene el log binario y asignarle un identificador. Para ello editamos el my.cnf añadiendo (o editando si ya las tiene) las siguientes entradas:

#Identificador único del servidor maestro
server-id=1
#Nombre del fichero binario donde se almacenarán las transacciones
log-bin=mysql-bin
sync_binlog=1
#Tamaño del fichero de log tras lo que se truncara
max-binlog-size=500M
expire_logs_days=4
innodb_flush_log_at_trx_commit=1

Como siempre que modificamos un my.cnf hay que reiniciar el servicio de MySql para que acepte los cambios.

Luego tenemos que hacer lo propio con el (o los) esclavo(s). Modificar el my.cnf con los siguientes parámetros y luego reiniciar el servicio:

#Indentificador único del esclavo
server-id=2
relay-log=mysqld-relay-bin
max-relay-log-size=500M
relay_log_purge=1

¡Muy bien! Ya tenemos un servidor maestro y un esclavo pero ahora necesitamos crear un usuario para que el esclavo se conecte al maestro y pueda leer el log de transacciones. Para ello vamos a crear un nuevo usuario llamado “replicador” (el nombre y pass puede variar, jeje) en el master con privilegios de “REPLICATION SLAVE“:

CREATE USER replicador IDENTIFIED BY 'elpassword';

Y luego le damos los permisos de REPLICATION SLAVE:

GRANT REPLICATION SLAVE ON *.* TO 'replicador'@'%' IDENTIFIED BY 'elpassword';
FLUSH PRIVILEGES;

Ok! Ya tenemos los servidores bien configurados y el usuario que usaremos como replicador por lo que lo próximo que tenemos que hacer es crear una copia inicial o “snapshot” de la base de datos que queremos replicar para luego poder indicar al servidor esclavo desde dónde tiene que empezar a leer.

Para hacer el snapshot primero ejecutamos las siguientes consultas:

FLUSH TABLES;
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;

Ten en cuenta que al hacer “READ LOCK” estamos bloqueando la tabla para que nadie cambie nada por lo que lo que viene a continuación deberíamos hacerlo lo más rápidamente posible.

El SHOW MASTER STATUS muestra dos valores que debemos anotar que son el “File” y “Position“. Necesitaremos indicarselos al servidor de réplica una vez hayamos cargado la copia inicial.

+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |     492 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

¡Muy bien! Vamos al servidor esclavo y lo terminamos de configurar.

Lo primero es cargar una copia de seguridad de base de datos que queremos replicar del master al esclavo (puedes usar el método que quieras, mysqldump, HeidSql, MySql Workbench…) y, una vez restaurada, configurar el esclavo e iniciarlo.

En este ejemplo vamos a suponer que el servidor maestro está alojado en 10.0.1.10. Fíjate que tenemos que indicar el File y la Position que hemos obtenido antes del SHOW MASTER STATUS:

CHANGE MASTER TO MASTER_HOST='10.0.1.10', MASTER_USER='replicador', MASTER_PASSWORD='elpassword', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=492, MASTER_PORT=3306;

START SLAVE;

Para terminar volvemos al maestro y desbloqueamos de nuevo las tablas para que puedan volver a editar datos:

UNLOCK TABLES;

¡Ya está! Si no ha pasado nada raro tendremos el servidor esclavo con la carga inicial funcionando y todo cambio en el master se replicara por arte de magia.

Si queremos saber el estado del servidor de réplica podemos usar la consulta:

SHOW SLAVE STATUS\G

Que nos mostrará un listado de datos. Yo miro el valor “Seconds_Behind_Master” que indica que “retraso” tiene el servidor esclavo respecto al maestro (si es NULL es que no va. Revisa el “Slave_IO_State” y “Last_Error”).

Ahora empieza a meter datos en la base de datos maestra y verás como ellos solitos aparecen en la esclava… ¡brujería! :-)

 

Espero que esto os sea útil.

Nos vemos Compilando!!