python my sql 기반 간단 한 대기 열 및 크로스 오 버 잠 금

============================================================================
오리지널 작품, 전재 허용.전재 할 때 원본 출처 와 본 성명 을 하이퍼링크 형식 으로 표시 해 주 십시오.
다음 을 입력 하 십시오:http://yunjianfei.iteye.com/blog/
============================================================================
 
다 중 프로 세 스 응용 개발 을 하 는 과정 에서 여러 프로 세 스 가 같은 자원 (임계 자원) 에 접근 하 는 상황 을 만 날 수 있 습 니 다. 전역 적 인 자 물 쇠 를 추가 하여 자원 의 동기 화 접근 을 실현 해 야 합 니 다 (같은 시간 에 하나의 프로 세 스 만 자원 에 접근 할 수 있 습 니 다).
 
예 를 들 어:
만약 에 우리 가 my sql 로 작업 대기 열 을 실현 한다 고 가정 하면 실현 하 는 과정 은 다음 과 같다.
1. Mysql 에서 Job 표를 만 들 고 대기 열 작업 을 저장 합 니 다. 다음 과 같 습 니 다.
create table jobs(
    id auto_increment not null primary key,
    message text not null,
    job_status not null default 0
);
message 는 작업 정 보 를 저장 하 는 데 사 용 됩 니 다. jobstatus 는 작업 상 태 를 표시 하 는데 두 가지 상태 만 있다 고 가정 합 니 다. 0: 대기 열 에서 1: 이미 대기 열 이 나 왔 습 니 다. 
 
2. 작업 표 에 새 데 이 터 를 넣 고 줄 을 서 는 생산자 프로 세 스 가 있 습 니 다.
insert into jobs(message) values('msg1');
 
3. 여러 소비자 프로 세 스 가 있다 고 가정 하고 job 표 에서 줄 서기 정 보 를 가 져 오 면 다음 과 같이 해 야 합 니 다.
select * from jobs where job_status=0 order by id asc limit 1;
update jobs set job_status=1 where id = ?; -- id 는 방금 얻 은 기록 id 입 니 다.
 
4. 프로 세 스 를 뛰 어 넘 는 자물쇠 가 없 으 면 두 소비자 프로 세 스 가 중복 되 는 정 보 를 동시에 얻 을 수 있 고 한 메시지 가 여러 번 소 비 될 수 있 습 니 다.이런 상황 은 우리 가 보고 싶 지 않 은 것 이다. 그래서 우 리 는 프로 세 스 를 뛰 어 넘 는 자 물 쇠 를 실현 해 야 한다.
 
여기에 제 가 아주 좋 은 글 을 붙 였 으 니 여러분 은 참고 하 셔 도 됩 니 다.
https://blog.engineyard.com/2011/5-subtle-ways-youre-using-mysql-as-a-queue-and-why-itll-bite-you
 
= = = = = = = = = = = = = = = = = = = = = = = = = = = 화려 한 분할 선 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
 
크로스 프로 세 스 의 잠 금 실현 에 대해 우 리 는 주로 몇 가지 실현 방식 이 있다.
1. 신 호 량
2. 파일 잠 금 fcntl
3. socket (포트 번호 바 인 딩)
4. signal
이 몇 가지 방식 은 각각 장단 점 이 있 는데 전체적으로 말 하면 앞의 두 가지 방식 이 좀 많 을 수 있 습 니 다. 여기 서 저 는 상세 하 게 말 하지 않 겠 습 니 다. 여러분 은 자 료 를 찾 아 보 셔 도 됩 니 다.
 
자 료 를 조사 할 때 my sql 에 자물쇠 가 실현 되 고 성능 에 대한 요구 가 높 지 않 은 응용 장면 에 적용 되 며 동시 다발 적 인 분포 식 방문 은 병목 이 있 을 수 있 습 니 다. 링크 는 다음 과 같 습 니 다.
http://dev.mysql.com/doc/refman/5.0/fr/miscellaneous-functions.html
 
나 는 python 으로 demo 를 실현 했다. 다음 과 같다.
 
파일 이름: glock. py
#!/usr/bin/env python2.7
#
# -*- coding:utf-8 -*-
#
#   Author  :   yunjianfei
#   E-mail  :   [email protected]
#   Date    :   2014/02/25
#   Desc    :
#

import logging, time
import MySQLdb


class Glock:
    def __init__(self, db):
        self.db = db

    def _execute(self, sql):
        cursor = self.db.cursor()
        try:
            ret = None
            cursor.execute(sql)
            if cursor.rowcount != 1:
                logging.error("Multiple rows returned in mysql lock function.")
                ret = None
            else:
                ret = cursor.fetchone()
            cursor.close()
            return ret
        except Exception, ex:
            logging.error("Execute sql \"%s\" failed! Exception: %s", sql, str(ex))
            cursor.close()
            return None

    def lock(self, lockstr, timeout):
        sql = "SELECT GET_LOCK('%s', %s)" % (lockstr, timeout)
        ret = self._execute(sql)

        if ret[0] == 0:
            logging.debug("Another client has previously locked '%s'.", lockstr)
            return False
        elif ret[0] == 1:
            logging.debug("The lock '%s' was obtained successfully.", lockstr)
            return True
        else:
            logging.error("Error occurred!")
            return None

    def unlock(self, lockstr):
        sql = "SELECT RELEASE_LOCK('%s')" % (lockstr)
        ret = self._execute(sql)
        if ret[0] == 0:
            logging.debug("The lock '%s' the lock is not released(the lock was not established by this thread).", lockstr)
            return False
        elif ret[0] == 1:
            logging.debug("The lock '%s' the lock was released.", lockstr)
            return True
        else:
            logging.error("The lock '%s' did not exist.", lockstr)
            return None

#Init logging
def init_logging():
    sh = logging.StreamHandler()
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s -%(module)s:%(filename)s-L%(lineno)d-%(levelname)s: %(message)s')
    sh.setFormatter(formatter)
    logger.addHandler(sh)
    logging.info("Current log level is : %s",logging.getLevelName(logger.getEffectiveLevel()))

def main():
    init_logging()
    db = MySQLdb.connect(host='localhost', user='root', passwd='')
    lock_name = 'queue'

    l = Glock(db)

    ret = l.lock(lock_name, 10)
    if ret != True:
        logging.error("Can't get lock! exit!")
        quit()
    time.sleep(10)
    logging.info("You can do some synchronization work across processes!")
    ##TODO
    ## you can do something in here ##
    l.unlock(lock_name)

if __name__ == "__main__":
    main()

main 함수 에서 l. lock (lock name, 10) 에서 10 은 timeout 을 나타 내 는 시간 이 10 초 입 니 다. 10 초 동안 자 물 쇠 를 가 져 오지 못 하면 되 돌아 와 뒤의 작업 을 수행 합 니 다.
 
 
이 demo 에 서 는 TODO 를 표시 하 는 곳 에서 소비자 가 job 표 에서 메 시 지 를 찾 는 논 리 를 여기에 둘 수 있 습 니 다.즉, 분할 선 이상 의:
   3. 여러 소비자 프로 세 스 가 있다 고 가정 하고 job 표 에서 줄 서기 정 보 를 가 져 오 면 다음 과 같이 해 야 합 니 다.
select * from jobs where job_status=0 order by id asc limit 1;
update jobs set job_status=1 where id = ?; -- id 는 방금 얻 은 기록 id 입 니 다.
 
이렇게 하면 여러 프로 세 스 가 임계 자원 에 접근 할 때 동기 화 되 어 데이터 의 일치 성 을 확보 할 수 있다.
 
테스트 할 때 두 개의 glock. py 를 시작 합 니 다. 결 과 는 다음 과 같 습 니 다.
[@tj-10-47 test]# ./glock.py 
2014-03-14 17:08:40,277 -glock:glock.py-L70-INFO: Current log level is : DEBUG
2014-03-14 17:08:40,299 -glock:glock.py-L43-DEBUG: The lock 'queue' was obtained successfully.
2014-03-14 17:08:50,299 -glock:glock.py-L81-INFO: You can do some synchronization work across processes!
2014-03-14 17:08:50,299 -glock:glock.py-L56-DEBUG: The lock 'queue' the lock was released.

첫 번 째 glock. py 는... 17: 08: 50 에 자 물 쇠 를 풀 었 습 니 다. 아래 의 glock. py 는 17: 08: 50 에 자 물 쇠 를 얻 었 습 니 다. 이것 이 완전히 가능 하 다 는 것 을 증명 할 수 있 습 니 다.
[@tj-10-47 test]# ./glock.py
2014-03-14 17:08:46,873 -glock:glock.py-L70-INFO: Current log level is : DEBUG
2014-03-14 17:08:50,299 -glock:glock.py-L43-DEBUG: The lock 'queue' was obtained successfully.
2014-03-14 17:09:00,299 -glock:glock.py-L81-INFO: You can do some synchronization work across processes!
2014-03-14 17:09:00,300 -glock:glock.py-L56-DEBUG: The lock 'queue' the lock was released.
[@tj-10-47 test]#
 
 

좋은 웹페이지 즐겨찾기