Sistemas Tolerantes a Fallas

45
Sistemas Tolerantes a Fallas Agustín Ramos @MachinesAreUs

description

Plática dada en el marco de SGCE 2014

Transcript of Sistemas Tolerantes a Fallas

Sistemas Tolerantes a Fallas

Agustín Ramos @MachinesAreUs

¿Cuál es el costo de una falla?

¿Cuál es el costo de una falla?

• Una pequeña molestia para algún usuario. !

• Una transacción (de negocio) no completada. • Datos inconsistentes.

!• No disponibilidad del sistema. O_o !

• Pérdida de un cliente. • O de muchos de ellos.

!• Muerte de una organización.

(Casi) Todos los sistemas son distribuidos

Las falacias de los sistemas distribuidos

1. La red es confiable. 2. La latencia es cero. 3. El ancho de banda es infinito. 4. La red es segura. 5. La topología no cambia. 6. Existe solo un administrador. 7. El costo del transporte es cero. 8. La red es homogénea.

Todos los sistemas fallan

http://www.ctlab.org/documents/How%20Complex%20Systems%20Fail.pdf

¿Cómo desarrollar sistemas tolerantes a fallas?

1. Aceptar: No puedes prevenir todas las fallas. 2. Evita los “puntos únicos de falla”. 3. Implementa mecanismos de detección de

errores. 4. Implementa corrección de errores.

• Si es posible y hace sentido. • e.g. patrón: Compensating Transactions ?

5. Contención de errores 1. Evita que se propaguen.

Consecuencias

Sistemas… • Creados de componentes pequeños,

independientes en tiempo de ejecución. • Distribuidos. • Con reintentos finitos. • Con respuestas apropiadas para casos de

falla.

Usa…

µ-Services

Patrones de Estabilidad

Patrón #1 Timeouts

Timeouts (1)

// Básico 1 myObject.wait(); // No uses esto por default myObject.wait(TIMEOUT); // Mejor usa esto !// Básico 2 myThread.join(); // No uses esto por default myThread.join(TIMEOUT); // Mejor usa esto

Timeouts (2)

// Utilizando el API de concurrencia de Java

<MyActionResult> myAction = <My Blocking Action>

ExecutorService executor = Executors.newSingleThreadExecutor(); Future<MyActionResult> future = executor.submit(myAction); MyActionResult result = null; try { result = future.get(); // No uses esto por default result = future.get(TIMEOUT, TIMEUNIT); // Mejor usa esto } catch (TimeoutException e) { // Si ocurre el timeout ... } catch (...) { ... }

Timeouts (3)

// Utilizando el SimpleTimeLimiter de Guava

Callable<MyActionResult> myAction = <My Blocking Action>

SimpleTimeLimiter limiter = new SimpleTimeLimiter(); MyActionResult result = null; try { result = limiter.callWithTimeout(myAction,

TIMEOUT, TIMEUNIT, false);

} catch (UncheckedTimeoutException e) { ... } catch (...) { ... }

Patrón #2 Circuit Breaker

Circuit Breaker (1)

Circuit Breaker (2)

Circuit Breaker (3)

public class CircuitBreaker implements MyResource { public enum State { CLOSED, OPEN, HALF_OPEN } final MyResource resource; State state; int counter; long tripTime; public CircuitBreaker(MyResource r) { resource = r; state = CLOSED; counter = 0; tripTime = 0L; } ...

Circuit Breaker (4)

... public Result access(...) { // resource access Result r = null; if (state == OPEN) {

checkTimeout(); throw new ResourceUnavailableException();

} try { r = resource.access(...); // should use timeout } catch (Exception e) {

fail(); throw e;

}

success(); return r;

}

...

Circuit Breaker (5)

...

private void success() {

reset();

}

private void fail() { counter++; if (counter > THRESHOLD) {

tripBreaker();

}

}

private void reset() { state = CLOSED; counter = 0;

}

...

Circuit Breaker (6)

...

private void tripBreaker() { state = OPEN; tripTime = System.currentTimeMillis(); } private void checkTimeout() { if ((System.currentTimeMillis - tripTime) > TIMEOUT) { state = HALF_OPEN; counter = THRESHOLD; } }

public State getState() return state; }

}

Patrón #3 Fail Fast

Fail Fast (1)

Fail Fast (2)

Fail Fast (3)

public class FailFastGuard { private FailFastGuard() {} public static void checkResources(Set<CircuitBreaker> resources) { for (CircuitBreaker r : resources) { if (r.getState() != CircuitBreaker.CLOSED) { throw new ResourceUnavailableException(r); }

}

}

}

Fail Fast (4)

public class MyService { Set<CircuitBreaker> requiredResources; // Initialize resources ... public Result myExpensiveAction(...)

{

FailFastGuard.checkResources(requiredResources);

// Execute core action ...

}

}

Patrón #4 Shed Load

Shed Load (1)

Shed Load (2)

Shed Load (3)

public class ShedLoadFilter implements Filter { Random random; public void init(FilterConfig fc) throws ServletException { random = new Random(System.currentTimeMillis()); }

public void destroy() { random = null; } ...

Shed Load (4)

...

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {

int load = getLoad();

if (shouldShed(load)) { HttpServletResponse res = (HttpServletResponse)response; res.setIntHeader("Retry-After", RECOMMENDATION); res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return;

}

chain.doFilter(request, response); } ...

Shed Load (5)

...

private boolean shouldShed(int load) { // Example implement if (load < THRESHOLD) { return false; } double shedBoundary = ((double)(load - THRESHOLD))/ ((double)(MAX_LOAD - THRESHOLD)); return random.nextDouble() < shedBoundary; } }

Patrón #5 Deferrable Work

Deferrable Work (1)

Deferrable Work (2)

Deferrable Work (3)

// Adaptive load variant ProcessingState state = initBatch(); while(!state.done()) { waitLoadBased();

state = processNext(state); } void waitLoadBased() { int load = getLoad(); long delay = calcDelay(load); Thread.sleep(delay); // try-catch left out for better readability

}

long calcDelay(int load) { // Simple example implementation if (load < THRESHOLD) { return 0L;

}

return (load – THRESHOLD) * DELAY_FACTOR; }

Patrón #6 Monitoreo

Referencias

• How Complex Systems Fail http://j.mp/HowComplexSystemsFail

!• Release It!

http://j.mp/ReleaseIt !

• Fault tolerance made Easy http://j.mp/FaultToleranceMadeEasy

!• Fault tolerance 101

http://j.mp/FaultTolerance101

Se MUY amable con tus usuarios Ellos te lo agradecerán :)

Preguntas

Agustín Ramos @MachinesAreUs