Cache Architecture Design

Cache Architecture Design

 

 

demand analysis

 

    Cache is a common technology to improve system read performance. For application scenarios with more reads and fewer writes, we often use cache to optimize.

 

    For example, for the user's balance information table account(uid, money), the business requirements are:

 

  1. Query the user's balance, SELECT money FROM account WHERE uid=XXX, accounting for 99% of the requests
  2. Change user balance, UPDATE account SET money=XXX WHERE uid=XXX, accounting for 1% of requests


    Since most of the requests are queries, we create a key-value pair from uid to money in the cache, which can greatly reduce the pressure on the database.

 

 

    Read operation flow

 

    After the data is stored in the database and the cache (uid->money), whenever the relevant data needs to be read (money), the operation process is generally as follows:

 

  1. Whether there is relevant data in the read cache, uid->money
  2. If there is relevant data money in the cache, return [this is the so-called data hit "hit"]
  3. If there is no relevant data money in the cache, read the relevant data money from the database [this is the so-called data miss "miss"], put it in the cache uid->money, and then return

    Cache hit rate = number of hit cache requests/total number of cache access requests = hit/(hit+miss)

    In the balance scenario of the above example, 99% of reads and 1% of writes, the hit rate of this cache is very high, which will be above 95%.

 

 

    question

 

    When the data money changes:

 

  1. Is it to update the data in the cache, or to retire the data in the cache?
  2. Is it to manipulate the data in the database first and then manipulate the data in the cache, or manipulate the data in the cache first and then manipulate the data in the database?
  3. Is there any room for optimization in the architecture of cache and database operations?

 

 

 

 

Updating Cache vs Retiring Cache

 

  • What is an update cache: data is written not only to the database, but also to the cache
  • What is the elimination of the cache: data will only be written to the database, not the cache, only the data will be eliminated

 

  • Advantages of updating the cache: the cache will not increase a miss, and the hit rate is high
  • Advantages of phasing out the cache: simplicity

 

The key to the choice: the complexity of updating the cache

 

    Case 1 : simply set the balance money to a value

 

  • 淘汰缓存的操作为deleteCache(uid)
  • 更新缓存的操作为setCache(uid, money)

    更新缓存的代价很小,此时我们应该更倾向于更新缓存,以保证更高的缓存命中率。

 

 

    情况二:如果余额是通过很复杂的数据计算得出来的,例如业务上除了账户表account,还有商品表

 

        product,折扣表discount

        account(uid, money)

        product(pid, type, price, pinfo)

        discount(type, zhekou)

 

    业务场景是用户买了一个商品product,这个商品的价格是price,这个商品从属于type类商品,type类商品在做促销活动要打折扣zhekou,购买了商品过后,这个余额的计算就复杂了,需要:

 

  1. 先把商品的品类,价格取出来:SELECT type, price FROM product WHERE pid=XXX
  2. 再把这个品类的折扣取出来:SELECT zhekou FROM discount WHERE type=XXX
  3. 再把原有余额从缓存中查询出来money = getCache(uid)
  4. 再把新的余额写入到缓存中去setCache(uid, money-price*zhekou)

    更新缓存的代价很大,此时我们应该更倾向于淘汰缓存。

 

 

建议

 

    淘汰缓存操作简单,并且带来的副作用只是增加了一次cache miss,建议作为通用的处理方式。

 

 

 

 

 

先操作数据库 vs 先操作缓存

 

       这个比较主要是针对写操作的,最根本性的问题就是保证数据的一致性,因为操作数据库和缓存不是原子性的,所以一旦中间出现什么错,有可能会导致数据不一致的情况,就要从下面情况来细说:

 

  1. add数据时,应该先写数据库,还是先写缓存?
  2. update数据时,如果选择淘汰cache,应该先更新数据库还是缓存?
  3. update数据时,如果选择更新cache,应该先更细数据库还是缓存?

 

 

add数据时,怎么选择?

 

       很显然,这是啥先写数据库,然后再写缓存,即使后面写缓存失败,顶多出现一次cache miss,最起码数据库已经持久化了;如果反过来,一旦写数据失败,那么缓存将会是脏数据,除非自己加上写缓存失败时,delete掉数据库的数据,这样太麻烦了。

 

 

 

update数据时,选择淘汰cache,那应该先更新哪个?

 

       记住这个准则,如果出现不一致,谁先做对业务的影响较小,就谁先执行。下面对两种情况进行业务上的比较:

 

       假设先写数据库,再淘汰缓存:第一步写数据库操作成功,第二步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧数据,数据不一致。



 

 

       假设先淘汰缓存,再写数据库:第一步淘汰缓存成功,第二步写数据库失败,则只会引发一次Cache miss。


    结论

 

    先淘汰缓存,再写数据库。

 

 

 

update数据时,选择更新cache,那应该先更新哪个?

 

       细想,无论是先更新数据库再更新缓存,还是先更新缓存再更新数据库,一旦后面的操作失败,都有可能出现数据不一致。所以,根据上面的解决方法,进行了改进:

 

    情况一:更新或新增缓存代价比较大

  1. 先删除缓存
  2. 然后更新数据库
  3. 等下次查询时,首先cache miss,查询出数据后再增加缓存

    情况二:更新或新增缓存代价小

  1.  先删除缓存
  2. 然后更新数据库
  3. 再将新数据新增到缓存

    情况三:如果缓存服务器很稳定,基本上能够保证修改或查询不会出问题

  1. 更新数据库
  2. 然后更新缓存

 

 

 

       

缓存架构优化

 

 

       前面提到的缓存架构有一个缺点:业务方需要同时关注缓存与DB,有没有进一步的优化空间呢?有两种常见的方案,一种主流方案,一种非主流方案。

 

 

主流优化方案

 

       服务化:加入一个服务层,向上游提供帅气的数据访问接口,向上游屏蔽底层数据存储的细节,这样业务线不需要关注数据是来自于cache还是DB。



 

    

非主流方案

 

       异步缓存更新:业务线所有的写操作都走数据库,所有的读操作都总缓存,由一个异步的工具来做数据库与缓存之间数据的同步,具体细节是:


 

  1. 要有一个init cache的过程,将需要缓存的数据全量写入cache
  2. 如果DB有写操作,异步更新程序读取binlog,更新cache

在(1)和(2)的合作下,cache中有全部的数据,这样:

 

  • 业务线读cache,一定能够hit(很短的时间内,可能有脏数据),无需关注数据库
  • 业务线写DB,cache中能得到异步更新,无需关注缓存

缺点

 

       这样将大大简化业务线的调用逻辑,存在的缺点是,如果缓存的数据业务逻辑比较复杂,async-update异步更新的逻辑可能也会比较复杂。

 

 

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326228196&siteId=291194637