25.10.06

Semáforos distribuidos con MySQL


Es común tener varios procesos que trabajan sobre un mismo recurso pero que no deben interferir uno con otro. En un solo procesador se resuelve facilmente (con los llamados locks o semáforos). Hacerlo en forma distribuida, cuando los procesos están en distintas CPUs es mas complicado. Con MySQL podemos implementar semáforos distribuidos de una forma extremadamente simple y que funciona en un solo servidor o en muchos.
Pongamos un ejemplo: tengo dos programas A y B. A quiere actualizar un stock sumandole 10 unidades y el B quiere dar de baja 3 unidades. El stock original es 100. Si A lee la cantidad 100, luego el B lee la misma cantidad antes de que A grabe 110 en la base de datos. Entonces A graba 110, pero B hace 100-3=97 y graba 97. Tendríamos que implementar algo que evite que B lea el stock antes de que A termine su operación (y no voy a hablar de transacciones, este es un ejemplo para ilustrar semáforos!).
Con las funciones de MySQL get_lock() y release_lock() podemos evitar estos conflictos.
Si A ejecuta algo como select get_lock('tocarstocks', 30) le va a devolver un 1 si el servidor le "otorga el lock". Cuando termina de trabajar tienen que hacer un select release_lock('tocarstocks').
Cuando B quiera tocar un stock tiene que ejecutar el mismo get_lock(). Si devuelve 1 significa que A no está ejecutando el código entre el get_lock() y el release_lock(), asi que es seguro modificar datos. Si A todavia no hizo el realease_lock() entonces B va a quedar bloqueado hasta que lo haga, o hasta que se supere el timeout (el 30 que pusimos como ejemplo). En este caso el select le va a devolver 0 (cero) y debe volver a intentar el get_lock o darse por vencido.

Lo interesante de esto es que funciona en una sola CPU, pero tambien cuando tenemos distintos procesos en distintos servidores y todos trabajando sobre la misma base de datos.