En aquest tema, explorarem els patrons de disseny escalable, que són solucions provades i reutilitzables per a problemes comuns en el disseny de sistemes escalables. Aquests patrons ajuden a garantir que els sistemes puguin gestionar un augment de la càrrega de treball sense perdre rendiment ni fiabilitat.
Objectius d'Aprenentatge
Al final d'aquest tema, hauràs de ser capaç de:
- Comprendre els conceptes bàsics dels patrons de disseny escalable.
- Identificar i aplicar diversos patrons de disseny escalable en diferents contextos.
- Avaluar els avantatges i desavantatges de cada patró.
Conceptes Bàsics
Què és un Patró de Disseny Escalable?
Un patró de disseny escalable és una solució arquitectònica que permet a un sistema gestionar un augment de la càrrega de treball de manera eficient. Aquests patrons ajuden a distribuir la càrrega, optimitzar l'ús dels recursos i mantenir la qualitat del servei.
Tipus d'Escalabilitat
- Escalabilitat Horitzontal (Scale-Out): Afegir més nodes al sistema per distribuir la càrrega.
- Escalabilitat Vertical (Scale-Up): Augmentar la capacitat dels nodes existents (més CPU, memòria, etc.).
Patrons de Disseny Escalable
- Patró de Compartició (Sharding)
Descripció: Divideix una base de dades o un conjunt de dades en parts més petites, anomenades "shards", que es distribueixen entre diferents servidors.
Avantatges:
- Millora el rendiment distribuint la càrrega.
- Permet l'escalabilitat horitzontal.
Desavantatges:
- Pot ser complex de gestionar.
- Requereix una lògica addicional per a la distribució i consulta de dades.
Exemple:
-- Suposem una base de dades d'usuaris que es divideix en dos shards -- Shard 1: Usuaris amb ID parells -- Shard 2: Usuaris amb ID senars -- Consulta en Shard 1 SELECT * FROM users WHERE id % 2 = 0; -- Consulta en Shard 2 SELECT * FROM users WHERE id % 2 = 1;
- Patró de Cache
Descripció: Emmagatzema dades freqüentment accedides en una memòria ràpida (cache) per reduir el temps de resposta i la càrrega sobre el sistema principal.
Avantatges:
- Redueix la latència.
- Disminueix la càrrega sobre la base de dades principal.
Desavantatges:
- Pot introduir complexitat en la gestió de la coherència de dades.
- Requereix espai addicional de memòria.
Exemple:
# Exemple d'ús de Redis com a cache en una aplicació Python import redis # Connexió a Redis cache = redis.StrictRedis(host='localhost', port=6379, db=0) # Emmagatzemar una clau-valor en la cache cache.set('user_123', 'John Doe') # Recuperar el valor de la cache user = cache.get('user_123') print(user) # Output: b'John Doe'
- Patró de Queue-Based Load Leveling
Descripció: Utilitza cues per gestionar la càrrega de treball de manera asíncrona, equilibrant la càrrega entre diferents components del sistema.
Avantatges:
- Millora la resiliència del sistema.
- Permet gestionar pics de càrrega de manera eficient.
Desavantatges:
- Pot introduir latència en el processament de tasques.
- Requereix una gestió addicional de les cues.
Exemple:
# Exemple d'ús de RabbitMQ per a la gestió de cues en una aplicació Python import pika # Connexió a RabbitMQ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # Declarar una cua channel.queue_declare(queue='task_queue') # Enviar un missatge a la cua channel.basic_publish(exchange='', routing_key='task_queue', body='Tasques a processar') print(" [x] Enviat 'Tasques a processar'") # Tancar la connexió connection.close()
- Patró de Microserveis
Descripció: Divideix una aplicació en serveis petits i independents que es poden desplegar i escalar de manera autònoma.
Avantatges:
- Facilita l'escalabilitat independent de components.
- Millora la mantenibilitat i la flexibilitat del sistema.
Desavantatges:
- Pot augmentar la complexitat de la gestió i la comunicació entre serveis.
- Requereix una infraestructura adequada per a la gestió de microserveis.
Exemple:
# Exemple de definició de serveis en un fitxer Docker Compose version: '3' services: user-service: image: user-service:latest ports: - "5000:5000" order-service: image: order-service:latest ports: - "5001:5001"
Exercicis Pràctics
Exercici 1: Implementació de Cache
Descripció: Implementa una solució de cache per a una aplicació web que consulta dades d'una base de dades freqüentment.
Instruccions:
- Configura una instància de Redis.
- Modifica l'aplicació web per utilitzar Redis com a cache.
- Mesura el rendiment abans i després de la implementació de la cache.
Solució:
# Exemple d'implementació de cache en una aplicació web amb Flask i Redis from flask import Flask, request import redis import time app = Flask(__name__) cache = redis.StrictRedis(host='localhost', port=6379, db=0) @app.route('/data') def get_data(): data_id = request.args.get('id') cached_data = cache.get(data_id) if cached_data: return cached_data # Simulació de consulta a la base de dades time.sleep(2) data = f'Dades per a {data_id}' # Emmagatzemar en la cache cache.set(data_id, data) return data if __name__ == '__main__': app.run(debug=True)
Exercici 2: Implementació de Queue-Based Load Leveling
Descripció: Implementa una solució de cues per gestionar tasques asíncrones en una aplicació.
Instruccions:
- Configura una instància de RabbitMQ.
- Modifica l'aplicació per enviar tasques a una cua.
- Implementa un consumidor que processi les tasques de la cua.
Solució:
# Exemple d'implementació de cues amb RabbitMQ en una aplicació Python import pika # Connexió a RabbitMQ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # Declarar una cua channel.queue_declare(queue='task_queue') # Enviar una tasca a la cua channel.basic_publish(exchange='', routing_key='task_queue', body='Tasques a processar') print(" [x] Enviat 'Tasques a processar'") # Tancar la connexió connection.close() # Consumidor de la cua def callback(ch, method, properties, body): print(f" [x] Processant {body}") # Connexió a RabbitMQ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # Declarar una cua channel.queue_declare(queue='task_queue') # Assignar el consumidor a la cua channel.basic_consume(queue='task_queue', on_message_callback=callback, auto_ack=True) print(' [*] Esperant tasques. Per sortir, premeu CTRL+C') channel.start_consuming()
Resum
En aquest tema, hem explorat diversos patrons de disseny escalable, incloent el patró de compartició, el patró de cache, el patró de queue-based load leveling i el patró de microserveis. Cada patró ofereix solucions específiques per a problemes comuns en el disseny de sistemes escalables, i la seva aplicació adequada pot millorar significativament el rendiment i la resiliència dels sistemes tecnològics.
En el proper tema, explorarem el balanceig de càrrega, una altra tècnica clau per garantir l'escalabilitat i la disponibilitat dels sistemes.
Curs d'Arquitectura Tecnològica
Mòdul 1: Fonaments de l'Arquitectura Tecnològica
- Introducció a l'Arquitectura Tecnològica
- Principis de Disseny de Sistemes
- Components d'una Arquitectura Tecnològica
- Models d'Arquitectura
Mòdul 2: Disseny de Sistemes Escalables
- Conceptes d'Escalabilitat
- Patrons de Disseny Escalable
- Balanceig de Càrrega
- Caché i Emmagatzematge en Memòria
Mòdul 3: Seguretat en l'Arquitectura Tecnològica
Mòdul 4: Eficiència i Optimització
- Optimització de Recursos
- Monitoratge i Manteniment
- Automatització de Processos
- Avaluació de Rendiment
Mòdul 5: Gestió de l'Arquitectura Tecnològica
- Governança de TI
- Gestió de Projectes Tecnològics
- Documentació i Comunicació
- Avaluació i Millora Contínua