如何实现分库分表
将原本存储于单个数据库上的数据拆分到多个数据库,把原来存储在单张数据表的数据拆分到多张数据表中,实现数据切分,从而提升数据库操作性能。分库分表的实现可以分为两种方式:垂直切分和水平切分。
水平:将数据分散到多张表,涉及分区键,
- 分库:每个库结构一样,数据不一样,没有交集。库多了可以缓解io和cpu压力
- 分表:每个表结构一样,数据不一样,没有交集。表数量减少可以提高sql执行效率、减轻cpu压力
垂直:将字段拆分为多张表,需要一定的重构
- 分库:每个库结构、数据都不一样,所有库的并集为全量数据
- 分表:每个表结构、数据不一样,至少有一列交集,用于关联数据,所有表的并集为全量数据
存储拆分后如何解决唯一主键问题
UUID:简单、性能好,没有顺序,没有业务含义,存在泄漏mac地址的风险
数据库主键:实现简单,单调递增,具有一定的业务可读性,强依赖db、存在性能瓶颈,存在暴露业务信息的风险
可以利用Redis,MongoDB,ZK等中间件:增加了系统的复杂度和稳定性
雪花算法
雪花算法原理
第一位符号位固定为0,41位时间戳,10位workId,12位序列号,位数可以有不同实现 优点:
- 每个毫秒值包含的ID值很多,不够可以变动位数来增加,性能佳(依赖workId的实现)。
- 时间戳值在高位,中间是固定的机器码,自增的序列在低位,整个ID是趋势递增的。
- 能够根据业务场景数据库节点布置灵活调整bit位划分,灵活度高。
缺点:
- 强依赖于机器时钟,如果时钟回拨,会导致重复的ID生成,所以一般基于此的算法发现时钟回拨,都会抛异常处理,阻止ID生成,这可能导致服务不可用。
如何解决不使用分区键的查询问题
- 映射:将查询条件的字段与分区键进行映射,建一张单独的表维护(使用覆盖索引)或者在缓存中维护
- 基因法:分区键的后x个bit位由查询字段进行hash后占用,分区键直接取x个bit位获取分区,查询字段进行hash获取分区,适合非分区键查询字段只有一个的情况
- 冗余:查询字段冗余存储
Session的分布式方案
- 采用无状态服务,抛弃session
- 存入cookie(有安全风险)
- 服务器之间进行Session同步,这样可以保证每个服务器上都有全部的Session信息,不过当服务器数量比较多的时候,同步是会有延迟甚至同步失败;
- IP绑定策略
使用Nginx(或其他复杂均衡软硬件)中的IP绑定策略,同一个IP只能在指定的同一个机器访问,但是这样做失去了负载均衡的意义,当挂掉一台服务器的时候,会影响一批用户的使用,风险很大;
- 使用Redis存储
把Session放到Redis中存储,虽然架构上变得复杂,并且需要多访问一次Redis,但是这种方案带来的好处也是很大的:
- 实现了Session共享;
- 可以水平扩展(增加Redis服务器);
- 服务器重启Session不丢失(不过也要注意Session在Redis中的刷新/失效机制);
- 不仅可以跨服务器Session共享,甚至可以跨平台(例如网页端和APP端)。