1. ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁 进行保护,相对于HashTable的synchronized锁的粒度更精细,并发性能更好,而 HashMap没有锁机制,线程不安全。
2. HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。
ConcurrentHashMap 是一种线程安全的高效Map集合
底层数据结构:
- JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现
- JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树
数据库的海量数据存储,方案有很多,常见的有: 分区、分表、分库和集群.
表分区(Partition)是一种数据存储方案,可以解决单表数据较多的问题,MySQL5.1开始支持表分区功能.
分区就是按照某种规则,把表数据对应的ibd文件拆分成多个文件来存储
从物理上来看,一张表的数据被拆到多个表文件存储了;从逻辑上来看,他们对外表现是一张表
增删改查的方式不会有什么变化,只不过底层MySQL底层的处理上会有变更,例如检索时可以只检索某个文件,而不是全部
优点:
• 可以存储更多的数据
• 查时可以根据规则只检索某一个文件,提高查询效率
• 数据统计时,可以多文件并行统计,最后汇总结果,提高统计效率
• 对于一些历史数据,如果不需要时,可以直接删除分区文件,提高删除效率
缺点:
- 分区字段必须是索引字段
- 分区方式不够灵活
- 只支持水平分区
分表: 创建表时按照自己的业务需求拆分表。一旦做了分表,无论是逻辑上,还是物理上,就从一张表变成了多张表
优点 :
• 拆分方式更加灵活
• 可以解决单表字段过多(垂直拆分)和数据过多(水平拆分)的问题
缺点:
• 增删改查时,需要自己判断访问哪张表
• 垂直拆分还会导致事务问题及数据关联问题:原本一张表的操作,变为多张表操作
首先,在微服务项目中,我们会按照项目模块,每个微服务使用独立的数据库,因此每个库的表是不同的,这种分库模式成为垂直分库。而为了保证单节点的高可用性,我们会给数据库建立主从集群,主节点向从节点同步数据。两者结构一样,可以看做是水平扩展。
优点:
• 解决了海量数据存储问题,突破了单机存储瓶颈
• 提高了并发能力,突破了单机性能瓶颈
• 避免了单点故障
缺点:
• 成本非常高
• 数据聚合统计比较麻烦
• 主从同步的一致性问题
• 分布式事务问题
排行榜是根据用户获取的积分来排序的.排行榜分为了实时榜单和历史榜单.
实时榜单查询量大,所以存在了Redis中,采用zSet结构,使用榜单生成时间做Key,用户id做value,用户所得积分做score(哪个月份对应哪个人,排名是多少).
历史榜单数据量较大,但是查询量较小,所以存在MySQL中.(不是本月的榜单都是历史榜单.)
在MySQL中防止数据过大,采用了分表的设计方案,每一个赛季对应一张新的表.查询是根据赛季标识查询一张表就可以.
历史赛季积分的生成分为三大步,核心就是把Redis中上一个赛季的完整数据保存到mysql中.
具体是:
1. 创建历史赛季表(一个赛季一张表)
2. 从redis中将数据保存到mysql中对应的赛季表中(保存的数据是上个赛季的信息)
3. 删除redis中历史赛季的数据
由于历史赛季积分的生成是每月的凌晨自动生成,所以使用定时任务xxl-job实现.为了保证三个任务按顺序执行,使用了子任务(任务链).