用缓存的角度看透sync.map

206 阅读3分钟

前言

说实话,如果不是因为金三银四,我也不会抽时间,翻开sync.map的源代码来温故知新。每次看sync.map的源代码,每次都是当天能记住其中的原理,隔了一段时间再看,脑海里会多了好多❓。干脆,趁这次有时间,有刚需,就整理一下自己对sync.map的理解。

介绍

sync.map结构体包含了最主要的两个字段---readdirty。故名思义,会让人联想到读写分离的概念思维。如果今天,还是用这种思维去理解sync.map,我列出了几个问题,如下:

  1. amended字段是什么含义❓
  2. expunged字段是什么含义❓
  3. 为什么在delete一个在read的key,是置nil,而不是删除❓
  4. read的数据是何时同步到dirty中的❓
  5. dirty的数据是何时同步到read中的❓ 我相信如果用读写分离的角度去解释上述的几个问题,很难自圆其说。如果换成缓存和数据库呢❓❓❓

类比思维

如果把read看作是缓存,那么dirty就非数据库不可了。

问题3

有了缓存和数据库,说实话,问题3就很好理解了。我们知道,如果在缓存中删除了一个key,当我们日后重复访问这个key的时候,会发生什么问题?是不是我们常常挂在嘴边的缓存穿透呢?如何解决缓存穿透?通常的做法,是不是赋一个默认值?巧了,sync.Map是不是就赋值了一个nil的默认值。

问题2

接着我们来思考问题2。我们先来讲一下expaunged的含义:表示这个key,只存在于read。如问题3所讲的,删除一个read中的key,value直接置为nil,那么,是什么时候将nil改为expaunged?我们动动双手,翻开源代码,会发现在Store方法中。如果换成更通俗的语言来讲,就是在问题4中,当read的数据同步到dirty的时候,会将nil的改成expauned。

问题4

紧接着我们来思考问题4。我们此处将read替换成缓存,dirty替换成数据库。缓存的数据是何时同步到数据库中?或者说缓存的数据为什么要同步到数据库中?是不是有种回写的意思?何时?当我们往sync.map插入一个既不在read,也不在dirty中的key,就会触发一次回写,顺便将read中的nil的改成expunged,正好和expunged含义所吻合--只存在于read。

问题5

古有缓存的数据同步到数据库中,现有数据库的数据同步到缓存。我们何时会从数据库的数据写到缓存呢?是不是缓存没有数据,就会将数据库的数据同步到缓存呢。用我们日常的开发思维套用在问题5也能很好地解释的通。问题又来了,何时发生?动动双手,翻开源代码,没错,在Load中,当我们的缓存未命中次数等于数据库的数据长度,怎么样,能理解了么?换成一句人话,就是缓存中没有数据,那干脆从数据库中取一份全量数据吧。

问题1

最后一个问题,amended字段含义正好和expunged相反,表示某个key,只存在于dirty中。表示这个数据只在数据库,缓存中没有哦。

结尾

有时候,当我们站在某个角度思考一个问题时,解释不通的时候,请换一个角度,说不定会有意想不到的收获。