Slide 1

Slide 1 text

LevelDB'on'S3'As'A'KVS

Slide 2

Slide 2 text

Who$am$I • Shunsuke)Aihara(@shunsukeaihara) • Ξυ΍ͬͯΔ • ܭࢉݴޠֶ • ը૾ॲཧɾԻ੠ॲཧɾݴޠॲཧͷϥΠ ϒϥϦ͍Ζ͍Ζॻ͍ͯΔ • h1ps:/ /bitbucket.org/aihara

Slide 3

Slide 3 text

ΞυαʔόΛϦϓϨΠεͨ͠ • Python(tornado)͔Βgo.+.kamiʹॻ͖׵͑ • όουϊ΢ϋ΢Λ՚ྷʹશճආ

Slide 4

Slide 4 text

50ms%or%DieΛ્Ή΋ͷ 1. Redis 2. Redis 3. Redis 4. GIL 5. etc

Slide 5

Slide 5 text

ՄೳͳݶΓڞ༗DBΛ৮Βͳ͍ ΫϥελͷϝϯςͭΒ͍ Redis͸γϯάϧεϨου

Slide 6

Slide 6 text

ΞυḉͰRDB৮Δౕ͸ԿΛ΍ͬͯ΋μϝ

Slide 7

Slide 7 text

AWSͰҰ൪҆ఆ͍ͯ҆͠෼ࢄDB͸?

Slide 8

Slide 8 text

S3

Slide 9

Slide 9 text

S3ͷ࢖͍υίϩ • S3Λͦͷ··KVSͱͯ͠࢖͏ • ผͷαʔϏεͰ࣮ࢪ&/&݁ߏεέʔϧ • shard&keyͱ͔ࢦఆͰ͖Δ͚ͲΞυαʔόͰ͸ϨΠςϯγͷ໰ ୊͕ • S3্ʹϑΝΠϧDBΛ഑ஔ • ϑΝΠϧDBΛόϥϚΩ

Slide 10

Slide 10 text

LevelDBΛS3ʹ഑ஔ • Norikra(+(Redshi/(+(PythonΫϥελͰ౷ܭ৘ใ΍ɺλʔήςΟ ϯά৘ใΛ͍ΖΜͳϥΠϑαΠΫϧͰߋ৽ • MessagepackܗࣜͰɺLevelDBʹ์ΓࠐΉ • h=ps:/ /github.com/shunsukeaihara/goDleveldbDobjectstorage/ • ֎෦ެ։൛

Slide 11

Slide 11 text

goଆ࣮૷ • golevelΛར༻ • ىಈ࣌ʹLevelDBΛμ΢ϯϩʔυ • λΠϚʔͰఆظతʹ࠶μ΢ϯϩʔυ • ҰͭͷLevelDBϑΝΠϧ΁ͷΞΫηε͸ҰͭͷGorou-neͰ • ϑΝΠϧͷચ͍ସ͑ͳΜ͔΋ಛʹؾʹ͠ͳ͍

Slide 12

Slide 12 text

CommandύλʔϯͬΆ͍࣮૷ • get(unpack)/set/expireͱ͔ • ଎౓ΑΓ΋ChannelΛ༻͍ͨՄಡੑΛ • MessagepackΛUnpackͨ͠σʔλ͸ΦϯϝϞϦͰΩϟογϡ • RedisͬΆ͍ExpireΛ࣮૷ • Expire΋:merͱChannelͰ࣮૷

Slide 13

Slide 13 text

gcTick := time.NewTicker(10 * time.Second) defer gcTick.Stop() updateTick := time.NewTicker(time.Duration(ldb.dbConf.Options.UpdateInterval) * time.Second) defer updateTick.Stop() for { select { case cmd := <-ldb.get: cmd.result <- ldb.execGet(cmd) case <-ldb.reset: ldb.cache = map[string]*cachedItem{} case <-updateTick.C: ldb.mu.RLock() if !ldb.downloading { go ldb.download(ctx, true) } ldb.mu.RUnlock() case msg := <-ldb.switchDB: oldDB := ldb.db oldPath := ldb.dbpath ldb.db = msg.db ldb.dbpath = msg.dbpath oldDB.Close() os.RemoveAll(oldPath) case <-ldb.expire: ldb.simpleExpire(1) case <-gcTick.C: ldb.simpleExpire(1) case msg := <-ldb.exit: ldb.db.Close() os.RemoveAll(ldb.dbpath) ldb.cache = map[string]*cachedItem{} msg <- struct{}{} break } }

Slide 14

Slide 14 text

IFͱ͔ • ςΩτ΢ʹΦϨΦϨDSL͔ΒδΣωͬͯΔ func GetCandidate(ctx context.Context, key string) ([]*data.Candidate, bool) { ldb, ok := levelDBFromContext(ctx, candidateDBKey) if !ok { panic("no candidate db in context") } res, ok, _ := ldb.getCandidate(key) return res, ok } func (ldb *LevelDB) getCandidate(key string) ([]*data.Candidate, bool, bool) { cmd := NewDBGetCmd(key, data.UnmarshalCandidates, int64(ldb.dbConf.Options.CacheExpire)) ldb.get <- cmd r := <-cmd.result if !r.ok { return nil, false, false } return r.val.([]*data.Candidate), r.ok, r.hit }

Slide 15

Slide 15 text

ͦΕͰ΋RedisɾMemcache͕ඞཁͳॴ΋…… • Redisࣗମ͸ਨ௚෼ࢄ/ਫฏ෼ࢄ • RedisΫϥελʹରͯ͠΋LevelDBΞΫηεͱಉ༷ɺػೳຖʹ 1Goru2neΛׂΓ౰ͯ • MessagepackΛUnpackͨ͠σʔλ΋Ωϟογϡ • ͬͪ͜ʹ΋RedisͬΆ͍expireઓུΛ࣮૷

Slide 16

Slide 16 text

݁Ռ • ςΩτ΢ʹॻ͍ͯे෼ૣ͍ • PythonͰॻ͍͍ͯͨαʔόͷ8ഒͷεϧʔϓοτ • 10ms-or-Die͙Β͍ͷ଎౓Ͱಈ࡞ • ܕ͕༗Δͷ͸େ෼خ͍͠ͱ͍͏ؾ࣋ͪ • ίʔυҾ͖ܧ͗࣌ͷܕͷ͋Γ͕ͨ͞