Share
Embed
Transcript
37 slides
-
1FSGFDU2VFVF͍͔ʹύʔϑΣΫτ͔ɺ ͋Δ͍3VCZͱ.Z42-Ͱ δϣϒΩϡʔΛ࡞ΔࢼΈʹ͍ͭͯ 5SFBTVSF%BUB OBSVTF How perfect PerfectQueue is, and
about an experience of making a job queue with Ruby and MySQL -
8IPJTOBSVTF w OLGϝϯςφ w ݹͷจࣈίʔυมϓϩάϥϜ w 3VCZίϛολ w ΦϒδΣΫτࢦεΫϦϓτݴޠ w
5%ͰόοΫΤϯυͷ3VCZΞϓϦέʔγϣϯΛ͍ ͍ͬͯ͡·͢ -
ͦͦ δϣϒΩϡʔͱ $%1+PC0CTFSWFSύλʔϯ IUUQBXTDMPVEEFTJHOQBUUFSOPSHJOEFYQIQ$%1+PC@0CTFSWFS &&#'&#$&# w '*'0 w ϑϩϯτΤϯυͱόοΫΤ ϯυΛૄ݁߹Խ
w εέʔϧΞτ͕༰қʹ w ෛՙٸ্ঢ࣌ͷ࣌ؒՔ͗ w োੑͷ্ -
1FSGFDU2VFVFͷಛ w "UMFBTUPODFTFNBOUJDT w 1FSNBOFOU4UPSBHF w 3%#.4 .Z42- w
SFUSZ IFBSUCFBUUJNFPVU w "UNPTUPODF w *EFNQPUFOUUBTLTVCNJTTJPO w 1FSGFDU2VFVF`TVOJRVFLFZ w 0UIFSVOJRVFOFTTPO"QQMJDBUJPO-BZFS USBEFP⒎ -
5IFMJGFPG UBTLT w 4VCNJU w "DRVJSF w 'JOJTI w %FMFUF
TVCNJU BDRVJSF EFMFUF GJOJTI SFMFBTF -
%BUB4USVDUVSF CREATE TABLE `queue` ( /* unique key (" at
most once) */ id VARCHAR(255) NOT NULL, /* for FIFO’s timeline */ timeout INT NOT NULL, /* opaque data */ data LONGBLOB NOT NULL, /* alive or finished */ created_at INT, PRIMARY KEY (id) ) -
λεΫͷೖ INSERT INTO `queue` (id, timeout, data, created_at) VALUES (
‘hive.123456789.unique_key’, /* unique key */ UNIX_TIMESTAMP(), /* now */ ’{“some”: “json”}’, /* opaque data */ NOW()); /* NOT NULL */ UJNFPVU now JOTFSU -
/* Run the following 2 queries exclusively: */ SELECT id
FROM `queue` WHERE timeout < UNIX_TIMESTAMP() AND created_at IS NOT NULL /* ະྃͷλεΫ */ ORDER BY timeout ASC LIMIT 5; UPDATE SET timeout=UNIX_TIMESTAMP()+300 /* alive_time */ WHERE id IN (?,?,?,?,?); λεΫͷऔಘ UJNFPVU now BDRVJSF +300 waiting... running... -
UPDATE `queue` SET timeout = UNIX_TIMESTAMP()+300 WHERE id = ?;
λεΫͷ࣮ߦதʜʜ UJNFPVU now IFBSUCFBU +300 waiting... running... )FBSUCFBUEVSJOHSVOOJOHBUBTLʜ -
λεΫͷྃ UPDATE `queue` SET timeout = UNIX_TIMESTAMP() + 720, created_at
= NULL UJNFPVU now pOJTI +720 ˢ SFUFOUJPO@UJNF running... +300 ˞SFUFOUJPO@UJNF ɹྃͯ͠ॏෳ࣮ߦΛ͙ͨΊɺ ɹҰఆ࣌ؒཧআͤͣʹอ͓࣋ͯ͘͠ -
ྃࡁΈλεΫͷআ DELETE FROM `queue` WHERE timeout <= UNIX_TIMESTAMP() AND created_at
IS NULL; UJNFPVU now EFMFUF +720 to be deleted... લड़ͷSFUFOUJPO@UJNFΛա͗ͨΒཧআɻ ىಈޙͱҰఆλεΫΛऔಘ͢Δ͝ͱʹ ্هΫΤϦΛ͛Δɻ -
֤ૢ࡞ʹ͍ͭͯ w 4VCNJUجຊతʹ*/4&35͢Δ͚ͩ w "DRVJSFഉଞͳͷͰΉ͔͍ͭ͠ w ฒྻॲཧʹ͓͚Δഉଞॲཧͱ͍͏ຊ࣭తͳ w 'JOJTIϓϥΠϚϦΩʔͰ61%"5&ͳͷͰ͔ΜͨΜ w
%FMFUF%&-&5&͢Δ͚ͩʜͱΈͤͯҙ֎ͱͤ͘ऀ -
λεΫऔಘͲ͏ഉଞ͢Δ͔ w A'0361%"5&AJTEJ⒏DVMUUPVTF w #FDBVTFJUPGUFODBVTFEFBEMPDL JGZPV XSJUF42-XJUIPVUFNVMBUJOH.Z42-`TNJOE ʙɹ'0361%"5&ɹʙ SELECT
id FROM `queue` WHERE … LIMIT 5 FOR UPDATE; UPDATE SET … WHERE id IN (?,?,?,?,?); -
λεΫऔಘͲ͏ഉଞ͢Δ͔ w -0$,5"#-&4CMPDLTPUIFSQSPDFTTOPUPOMZ BDRVJSJOHUBTLTCVUBMTPTVCNJUUJOHUBTLT */4&35 BOEIFBSUCFBUT ʙɹ-0$,5"#-&4ɹʙ SET autocommit=0; LOCK
TABLES `queue` WRITE; SELECT id FROM `queue` WHERE … LIMIT 5; UPDATE SET … WHERE id IN (?,?,?,?,?); COMMIT; UNLOCK TABLES; -
λεΫऔಘͲ͏ഉଞ͢Δ͔ w (&5@-0$, VTFSMPDL XPSLTpOF ʙɹ(&5@-0$,ɹʙ GET_LOCK(`queue`); SELECT id FROM
`queue` WHERE … LIMIT 5; UPDATE SET … WHERE id IN (?,?,?,?,?); RELEASE_LOCK(`queue`); -
$POqJDUXJUI%&-&5& আͪλεΫͱBDRVJSFͪλεΫɺͱʹUJNFPVUʹ ΑΔJOEFY্ͷಉ͡ྖҬʹଘࡏ͢Δɻ ˠҙͯ͠ΫΤϦΛॻ͔ͳ͍ͱσουϩοΫ͢Δ͜ͱ͕͋Δ now EFMFUF +720 to be deleted...
UJNFPVU BDRVJSF waiting... running... -
ྃࡁΈλεΫͷআW GET_LOCK(`queue`); DELETE FROM `queue` WHERE timeout <= UNIX_TIMESTAMP() AND
created_at IS NULL; RELEASE_LOCK(`queue`); UJNFPVU now EFMFUF +720 to be deleted... 3VOEFMFUFRVFSZBGUFSUIFMPDLOBNFEUIFUBCMF લड़ͷSFUFOUJPO@UJNFΛա͗ͨΒཧআɻ ىಈޙͱҰఆλεΫΛऔಘ͢Δ͝ͱʹ ͜ͷΫΤϦΛ͛Δɻ -
ྃࡁΈλεΫͷআW GET_LOCK(`queue`); DELETE FROM `queue` WHERE timeout <= UNIX_TIMESTAMP() AND
created_at IS NULL; RELEASE_LOCK(`queue`); UJNFPVU now EFMFUF +720 to be deleted... લड़ͷSFUFOUJPO@UJNFΛա͗ͨΒཧআɻ ىಈޙͱҰఆλεΫΛऔಘ͢Δ͝ͱʹ ͜ͷΫΤϦΛ͛Δɻ શͯͷϫʔΧʔΛಉ࣌ʹىಈ͢Δͱɺ ͠Β͘ͷؒআΫΤϦ͕ඈͳ͍ -
$POqJDUXJUI%&-&5& আͪλεΫͱऔಘͪλεΫɺUJNFPVUʹΑΔJOEFY্Ͱಉ͡ྖҬ ʹଘࡏ͢Δ ˠআͪλεΫ͕૿͑ΔͱɺλεΫऔಘͷεϧʔϓοτ͕Լ͢Δ ˠఆظతʹ%&-&5&ΫΤϦ͕ඈͿΑ͏ʹཚͰࢄͤ͞Δ now EFMFUF +720 to be
deleted... UJNFPVU BDRVJSF waiting... running... -
$POqJDUXJUI%&-&5& আͪλεΫͱऔಘͪλεΫɺUJNFPVUʹΑΔJOEFY্Ͱಉ͡ྖҬʹଘࡏ͢Δ ˠऔಘͪλεΫ͕૿͑ΔͱɺྃࡁΈλεΫͷআʹ͕͔͔࣌ؒΔ ˠλεΫͷऔಘ͕ϒϩοΫ͞Εͯεϧʔϓοτ͕Լ͕Δ ɹʢόοΫΤϯυͷෆௐ࣌ʹΛѱԽͤ͞Δʣ ˠ͕ඞཁ now EFMFUF +720 to
be deleted... UJNFPVU waiting... running... -
$POqJDUXJUI%&-&5& औಘͪλεΫͱআࡁΈλεΫͷଘࡏ͢ΔྖҬΛ͚ͨ w औಘͪλεΫআͪλεΫ͕ͨ·ͬͯ҆ఆ͕ͯ͠ग़Δ Α͏ʹͳͬͨ w আΫΤϦͷσουϩοΫରࡦ͕ෆཁʹͳͬͨ w λεΫͷऔಘͱྃλεΫͷআ͕ฒߦʹΔ ˠεϧʔϓοτ্
now EFMFUF waiting... running… now-10ԯඵ 13ԯඵ BDRVJSF to be deleted... -
/FUXPSLMBUFODZ w (&5@-0$, VTFSMPDL XPSLTpOF XIJMFOFUXPSLJTpOF w &$ͱ3%4ͷωοτϫʔΫԆ͕ѱԽ͢Δͱɺ εϧʔϓοτ͕ഒѱԽ͢Δ ʙɹBDRVJSJOHUBTLTXJUI(&5@-0$,
ɹʙ GET_LOCK(`queue`); SELECT id FROM `queue` WHERE … LIMIT 5; UPDATE SET … WHERE id IN (?,?,?,?,?); RELEASE_LOCK(`queue`); -0$, 355 -
%BUB4USVDUVSF CREATE TABLE `queue` ( /* unique key (" at
most once) */ id VARCHAR(255) NOT NULL, /* for FIFO’s timeline */ timeout INT NOT NULL, /* opaque data */ data LONGBLOB NOT NULL, /* alive or finished */ created_at INT, /* Who get this task */ owner BIGINT(21) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (id) ) -
UPDATE `queue` JOIN ( SELECT id FROM `queue` FORCE INDEX
(`index_queue_on_timeout`) WHERE 1300000000<timeout AND timeout<=UNIX_TIMESTAMP() ORDER BY timeout ASC LIMIT :max_acquire FOR UPDATE) AS t1 USING(id) SET timeout=:next_timeout, owner=CONNECTION_ID() SELECT id, timeout, data, created_at, resource FROM `#{@table}` WHERE timeout = ? AND owner=CONNECTION_ID() "DRVJSJOHUBTLTXJUIPVUUBCMFMPDLJOH 4FMFDU.BSL ˣ .BSL4FMFDU 28IBUJT$0//&$5*0/@*% "1SPDFTT*%PGUIF.Z42-DPOOFDUJPO 28IZJUVTFT4&-&$5JO61%"5& ".Z42-EPFTO`UPQUJNJ[F61%"5&RVFSZXJUI -*.*5DMBVTFʜ 2*TA'0361%"5&ATBGF "4BGFCFDBVTF*XSPUFUIJTXJUIJNBHJOH.Z42-`T NJOE -
λεΫͷऔಘ UJNFPVU now ᶄ4&-&$5 waiting... read lock! ᶃ61%"5& write lock!
XJUIPVUA'0361%"5&A -
λεΫͷऔಘ UJNFPVU now ᶄ61%"5& waiting... write lock! ᶃ61%"5& write lock!
DEADLOCK XJUIPVUA'0361%"5&A -
UPDATE `queue` JOIN ( SELECT id FROM `queue` FORCE INDEX
(`index_queue_on_timeout`) WHERE 1300000000<timeout AND timeout<=UNIX_TIMESTAMP() ORDER BY timeout ASC LIMIT :max_acquire FOR UPDATE) AS t1 USING(id) SET timeout=:next_timeout, owner=CONNECTION_ID() SELECT id, timeout, data, created_at, resource FROM `#{@table}` WHERE timeout = ? AND owner = CONNECTION_ID() "DRVJSJOHUBTLTXJUIPVUUBCMFMPDLJOH 4FMFDU.BSL ˣ .BSL4FMFDU #ZUIJTTUSBUFHZ JUBWPJETOFUXPSL MBUFODZJTTVF.PSFPWFSJUDBO BDIJFWFGBTUFSUBTLBDRVJSJOH BCPVUY