看韩路彪老师写的《看透Spring MVC:源代码分析与实践》,提到了海量数据问题解决的知识,在此记录总结下。
系统运行速度问题主要集中在海量数据操作问题和高并发问题。海量数据操作问题上,解决方法有:
- 缓存、页面静态化
- 数据库优化
- 分离活跃数据
- 批量读取、延迟修改
- 读写分离
- 分布式数据库
- NoSQL
缓存、页面静态化
缓存
缓存主要分为存在内存中、使用缓存框架。
存在内存中大多是存在Map这种数据结构中。缓存框架则包括Ehcache、Memcache和Redis等。
缓存的主要问题是何时创建缓存以及失效机制。另外在之前在看redis的相关知识时,看到一个名词:“击穿”,指的是客户端在缓存中获取不到数据,直接从数据库去拉取数据。
我之前的想法是赋予一个初值。这本书里给出一个例子是:保存文章评论的缓存,有的文章就是没有评论(比如我写的),那每次查询评论,缓存没有,总是查询数据库,缓存就没有用处。书中给出的解决方案是创建专门的类存放没有评论的缓存,这样查询时可以知道是因为第一次创建缓存还是本身就没有评论。
但也是在之前看redis的东西时,看到的一个常见问题:redis与数据库的同步问题。这也是缓存这个方法存在的问题。
页面静态化
页面静态化就是将程序生成的页面保存起来,不需要每次调用都生成页面。
页面静态化可以在程序中使用模板技术生成,如常用的Freemarker和Velocity都可以根据模板生成静态页面,另外也可以使用缓存服务器在应用服务器的上一层缓存生成的页面,如可以使用Squid,另外Nginx也提供了相应的功能。(这段话是抄自该书,我还不了解,留待以后)。
数据库优化
数据库优化中常用的有表结构优化、SQL语句优化、分区和分表、索引优化、使用存储过程代替直接操作等,另外有时候合理使用冗余也能获得非常好的效果。
SQL语句优化:其中比较重要的是处理逻辑的优化。需要根据实际情况,对具体数据进行sql查询处理,通过分析执行时间和执行日志来找出问题和能够进行优化的点。
分表:当表中的数据能够分为几种固定类型,而同时对多种类型进行操作的情况比较少时,可以进行分表。另一个分表的方法是将一个表中不同类型的字段分到不同的表中保存,这样适用于对其中几个类型的增删改比较多,并且不影响其他类型时。
分区:上面提到的第二种方法,会导致查询完整数据时比较麻烦。因此可以使用分区,也可以综合来使用。分区是按照某种规则将数据分到不同的区进行保存,查询的时候数据若在同一个区内,可以只对一个区进行操作,更加快速,并且对程序是透明的。
索引优化:感觉就像“炼丹”,哪些字段上索引更好,使用什么类型的索引更好,需要测试。
存储过程:在操作过程复杂而且调用频率高的业务中,可以通过使用存储过程代替直接操作来提高效率,因为存储过程只需要编译一次,而且可以在一个存储过程里面做一些复杂的操作。
业务逻辑优化:这是要看具体数据,具体的项目需求。进行分析。
分离活跃数据
虽然有些数据总数据量非常大,但是活跃数据并不多,这种情况就可以将活跃数据单独保存起来从而提高处理效率。
就像银行里面,办了银行卡的、有手机银行的人数很多,但月活其实占比不高。因此存储活跃数据在单独的数据库,根据查询目标,可以只在更少的数据量中进行查询。查不到再去不活跃的数据中进行查询。
批量读取和延迟修改
这两种都是通过减少操作的次数来提高效率。
批量读取
将多次查询合并到一次进行。例如批量导入信息时,需要对每条信息进行检查,在数据库中查询是否存在等情况。这时可以将所有数据的字段保存在一个变量里,使用in语句统一查询。
高并发下,还可以将多个请求的查询合并到一次进行。可以用异步请求来处理。
延迟修改
针对高并发而且频繁修改(包括新增)的数据。这种情况可以先将需要修改的数据暂时保存到缓存中,然后定时将缓存中的数据保存到数据库中,程序在读取数据时可以同时读取数据库中和缓存中的数据。
这也有点像redis中的渐进式rehash。
读写分离
读写分离就是在数据库集群上实现的。集群中写入操作主要有一个数据库服务器进行,称为主服务器。其他服务器负责读取操作,称为从服务器。
主从之间的同步,在底层实现,主服务器可以先给一部分从服务器同步,然后这一部分从服务器再和其他从服务器进行同步。
同步方式有多种:数据库的热备份、软硬件的配合。集群上同时还需考虑负载均衡问题。
分布式数据库
读写分离将多个请求分到不同的服务器上。分布式数据库则是将复杂的单个请求分到多个服务器,这里服务器与读写分离的服务器不同,读写分离的服务器存储的是相同的数据库,而分布式数据库是将不同的表放在不同的数据库,数据库放在不同的服务器中。
分布式的服务器中还可以进一步进行读写分离。分布式本身就难以满足ACID,CAP(consistency、availability、partition tolerance)难以同时满足。所以还有如事务处理这样的问题需要解决,因此有分布式事务:两阶段提交、三阶段提交、TCC(try-confirm-cancel)、PAXOS协议。还有分布式锁的实现:redis、zookeeper等。
NoSql
NoSql指的是非结构化数据。根据存储类型可以分为以下几类nosql:
1、宽列存储、列簇:Hbase/Hadoop、Cassandra、Hypertable、Amazon SimpleDB、Apache Flink、Elassandra等。
2、文档存储:MongoDB、CouchDB等。
3、键值对存储:Redis、RocksDB、Berkeley DB等。
4、图存储:Neo4J、ArangoDB, FaunaDB, OrientDB, gunDB等。
5、多模型:ArangoDB、FoundationDB等。
6、对象存储:Versant、db4o等。
7、Grid & Cloud :GridGain、Crate Data等。
8、xml:EMC Documentum xDB、Berkeley DB XML等。
9、多维:Intersystems Cache、GT.M等。
10、多值:U2、TigerLogic PICK等。
11、事件源:Eventsourcing for Java (es4j)
12、时间序列、时间流:Axibase、quasardb等。
个人觉得目前比较多应用的是列存储中的数据库、MongoDB、键值对存储的。但这跟具体业务相关。
每一个数据库都能开一个系列总结学习,在这只是总结一下。