读多写少,优化性能 application -> cache(快) -> DB(慢)
缓存命中率 = 命中的 / 总的
写入操作时,更新缓存(写入DB && 写入缓存 计算简单的时候,直接更新,增加一次命中率)/淘汰缓存(写
入DB,只淘汰数据,计算复杂时,比更新操作简单,但会增加一次不命中)
处理时应先写入缓存,再写入DB,如果DB失败,则缓存多一次失效。如果先DB后缓存,这时缓存失败了,则缓存数据和DB数据出现不一致
实现方案:中间加入服务层/写请求都到DB,都请求都到cache,异步工具来做db与缓存间的同步(这种太复杂了点吧)
服务化是向业务方屏蔽底层cache与db复杂性的一种通用解决方式
用户想查找自己的订单列表,分页,列表会变 (uid -> list<oid> ,uid的订单新增时,删除缓存)
频繁删除redis key会产生很多内存碎片,导致内存占用率越来越大,最后不得不重启释放内存
连接池每次取出一个连接后并发执行,想串行化这种操作,考虑在获取连接时按照业务ID取模
---------------------------------------------------------------------------------------------------------
例如订单表,业务上对用户和商家都有订单查询需求:
Order(oid, info_detail)
T(buyer_id, seller_id, oid)
如果用buyer_id来分库,seller_id的查询就需要扫描多库。
如果用seller_id来分库,buyer_id的查询就需要扫描多库。
这类需求,为了做到高吞吐量低延时的查询,往往使用“数据冗余”的方式来实现,就是文章标题里说的“冗余表”:
T1(buyer_id, seller_id, oid)
T2(seller_id, buyer_id, oid)
同一个数据,冗余两份,一份以buyer_id来分库,满足买家的查询需求;
一份以seller_id来分库,满足卖家的查询需求。
具体实现:
双写
异步消息投递
通过log接触耦合,线下异步写
谁先来?哪种对业务影响小哪种先来,一切为业务服务
以上文的订单生成业务为例,buyer和seller冗余表都需要插入数据:
T1(buyer_id, seller_id, oid)
T2(seller_id, buyer_id, oid)
用户下单时,如果“先插入buyer表T1,再插入seller冗余表T2”,当第一步成功、第二步失败时,出现的业务影
响是“买家能看到自己的订单,卖家看不到推送的订单”
相反,如果“先插入seller表T2,再插入buyer冗余表T1”,当第一步成功、第二步失败时,出现的业务影响是“卖家能看到推送的订单,卖家看不到自己的订单”
由于这个生成订单的动作是买家发起的,买家如果看不到订单,会觉得非常奇怪,并且无法支付以推动订单状态的流转,此时即使卖家看到有人下单也是没有意义的。
因此,在此例中,应该先插入buyer表T1,再插入seller表T2。
一致性保证:
线下离线扫描,对比两个表,不一致进行修补
写入表,写入log,线下增量扫描log,对比两个表,不一致进行修补canal
写入表,发送消息msg1,写入另一个表,发送消息msg2,检查两个消息的间隔,确定是否需要修补