关于并行计算的概念有很是多,硬件落地其实就只有两种,CPU上的并行计算和GPU上的并行计算,GPU作点积这样的矢量计算(矩阵计算)有优点,但目前还运行不了操做系统和数据库,比较多用于研究性质的计算。在咱们生产系统中运用最多的是CPU上的并行计算,其落地方式也只有两种,多线程和多进程。围绕多线程、多进程结合通讯技术的灵活设计,它的应用范围很是普遍,不光用于并行计算,也是大部分的服务器技术、分布式技术、中间件技术的重要实现技术, java
Fourinone同时提供多线程和多进程的并行计算,而且能实现二者之间的无缝切换,而不须要改一行业务计算的逻辑代码,计算过程当中还能保证高容错,一个工人故障会重投任务到其余工人执行,并有超时终止等支持。 redis
1、Fourinone如何实现多线程并行计算
实现多线程并行计算只须要一个工头实现类就够了,除外不须要依赖任何计算服务,这个例子位于下载包的分布式计算补充demo目录下,CtorMul .java: 算法
import com.fourinone.Contractor; import com.fourinone.WareHouse; import com.fourinone.WorkerLocal; public class CtorMul extends Contractor { public WareHouse giveTask(WareHouse inhouse) { /*WorkerLocal[] wks = getWaitingWorkers("WorkerMul"); System.out.println("wks.length:"+wks.length);*/ //生成5个多线程工人,并设置业务实现类 WorkerLocal[] wks = getLocalWorkers(5); for(int j=0;j<wks.length;j++) wks[j].setWorker(new WorkerMul()); //生成15个计算任务 WareHouse[] tasks = new WareHouse[15]; for(int i=0;i<15;i++){ tasks[i]=new WareHouse("taskId",i+""); } //让多个工人并行争抢处理多个任务,而且高容错,堵塞直到返回全部任务结果。 WareHouse[] result = doTaskCompete(wks, tasks); for(int i=0;i<result.length;i++){ System.out.println(i+":"+result[i]); } return inhouse; } public static void main(String[] args) { CtorMul cd = new CtorMul(); cd.giveTask(null); cd.exit(); } }
直接用java编译运行CtorMul.java便可完成一个本地多线程并行计算:
javac -cp fourinone.jar; *.java
java -cp fourinone.jar; CtorMul sql
咱们看到CtorMul.java程序main函数里先new了一个CtorMul实例,而后调用它的giveTask方法,在这个方法里,工头本身生成必定数量的线程帮助本身完成计算任务,并在计算结束后程序退出。完成计算任务的函数是doTaskCompete,它有两个参数,把全部工人和全部任务扔给它,而后堵塞等待全部计算完成,返回一个结果集。 数据库
多线程并行计算方式的优缺点:
因为只须要一个工头实现类就能够完成多线程并行计算,因此它很是好集成,容易嵌入到你的业务系统中去,可是多线程并行计算有很大局限性,它首先只能在本地,没法作分布式并行计算去利用多台机器的cpu资源,还有多线程的容错性较差,因为多线程工人和主线程工头都在一个jvm进程里,一个线程出故障容易致使整个jvm进程挂掉,也比较难切换到其余线程运行。 安全
2、Fourinone如何实现多进程并行计算
如何将上面的多线程并行计算无缝切换成一个多机的分布式多进程并行计算,咱们把CtorMul.java里面引用到的WorkerMul.java工人实现类打开: 服务器
import com.fourinone.MigrantWorker; import com.fourinone.WareHouse; public class WorkerMul extends MigrantWorker { public WareHouse doTask(WareHouse inhouse) { String taskId = inhouse.getString("taskId"); System.out.print("taskId"+taskId+"任务处理中..."); try{Thread.sleep(3000L);}catch(Exception ex){} System.out.println("taskId"+taskId+"处理完成。"); return new WareHouse("result", "ok"); } public static void main(String[] args) { WorkerMul wd = new WorkerMul(); wd.waitWorking(args[0],Integer.parseInt(args[1]),"WorkerMul"); } }
这个工人实现类的doTask接口里,只是简单打印了任务编号和sleep了3秒模拟处理任务,而后返回。可是咱们注意到它有个main函数的,上面的多线程并行计算只是new了WorkerMul 的实例做为业务实现类传入,可是并无运行工人的main函数让它启动起来,咱们可让WorkerMul 独立启动,它就是一个工人服务进程,能够在多台机器上启动多个这样的工人进程,并监听在不一样的ip和端口。 多线程
咱们再观察到前面的CtorMul .java第一段的代码注释掉了,根据Fourinone的架构设计,咱们知道工人服务进程启动后,会到职介者(ParkServer)去注册,ParkServer实现了ZooKeeper的全部功能和领导者选举算法,而后工头经过getWaitingWorkers获取到线上工人,并远程调用工人完成计算任务,详细能够参考:多机并行计算指南。 架构
咱们把CtorMul .java第一段的代码的注释取消,改把第二段用于本地多线程的代码注释掉,其余代码不用变。而后咱们启动两个工人作多进程并行计算,从新编译后运行顺序以下:
java -cp fourinone.jar; ParkServerDemo
java -cp fourinone.jar; WorkerMul localhost 6001
java -cp fourinone.jar; WorkerMul localhost 6002
java -cp fourinone.jar; CtorMul 并发
能够看到咱们把并行计算从多线程切换到了多进程,可是工人的任务实现逻辑doTask仍然一行代码不改动。多进程方式须要独立运行多个工人和职介者服务,比多线程方式要麻烦和复杂,可是它能带来更强大的分布式计算扩充能力和更好的容错稳定性,咱们在运行过程当中,能够Ctrl+C把其中一个正在计算的工人关掉,会发现工头抛出调用异常,可是计算并未停止,而是将该任务重投到另外一个工人上去作,只要集群还剩一个工人,计算就不会受影响,只是计算效率会下降,时间会延长。
总结:有人问Fourinone为何不设计成Hadoop,Spark,Storm这样的动态任务投放方式,实际上Fourinone如今的方式要更灵活,若是要事先定义好DAG那样的任务流程图出来,并考虑如何分配资源,作到最后会发现都走到资源隔离管理的路上去了,那还不如开始去作Docker。从这点上看Fourinone的并行计算,更接近MPI,可是相对于MPI抽象概括出了并行计算的角色、方法和模式。而且Fourinone也没有Hadoop和Spark的shuffle机制的烦恼,若是Fourinone作成一个资源隔离框架+DAG任务平台,那是不可能实现出一个功能强大的并行数据库引擎的,连作些灵活的机器学习算法并行化都困难,
3、再谈并行数据库引擎CoolHash
关于CoolHash,最好你们能直接它启动起来,而后各类测,与其谈太多架构算法,不如边测试边观察数据,经过数据去思考。下面是coolhash运行界面,不须要安装,启动很简单。
运行机器能够是普通的笔记本或者台式机,操做系统不限,CoolHash能竭尽利用你机器的最大性能,固然生产线上仍是要运行在pc server上,从8核的虚拟机到24核的实体机都是能够的,不须要ssd,有更好。相信你们对相同机器配置下,关系型数据库、内存数据库的基本性能都有所了解,能够对比下性能的差别。
每一个数据库厂商出示的测试报告都是宣称本身最好,因此不要去相信宣传的,好比做者亲身经历的couchdb单机能力就没有redis快,客户方把couchdb公司的人请来最后也是同样的结果。用户亲手测试的结果更有说服力,看到底能不能在单机上作到百万的TPS,达到硬件的极限,用户必定要作到本身内心有数,若是你对测试结果有什么疑问,能够直接到Fourinone技术群里去提问。
想强调的一点,CoolHash是持久化的,几乎同时把数据从内存刷到硬盘,因此它的容量是硬盘容量,不是内存容量,这点和redis很不同,也就是数据容量超过内存大小时,仍是运行稳定的,并且性能不降低(准确的说是不高于所在硬盘分区容量的70%-80%,操做系统建议不要超过这个安全比例),redis是严禁数据容量接近内存一半的,由于redis碰到刷硬盘的瞬间占用内存会膨胀一倍,
有人问,我一次写入200万数据,为何CoolHash里只有100万,是否是丢了数据?那是由于CoolHashMap默认最大容量为1百万条数据,可根据内存大小调整HASHCAPACITY配置项,在配置文件里改下就能够了。数据库引擎是严禁有任何数据丢失错乱问题的。
网上有人诋毁CoolHash不支持高并发,最好的办法就是亲自检验,不用理会喷子。下载包里自带了并发测试程序:
CoolHashTestRun.java是多个客户端进程高并发大数据量读写测试
ThreadClient.java是多个客户端线程高并发大数据量读写测试
在CoolHash的最第一版本只支持多进程的客户端,出于安全隔离性考虑限制了一个jvm里模拟多线程客户端访问,可是这跟数据库服务端引擎没有关系的, 引擎一直都是支持高并发访问的。如今多线程客户端也都开通了。
CoolHash更重要的能力还不只是高性能读写,灵活检索能力是衡量数据库引擎能力的标志,它能支持key和value的同时模糊检索,而且可支持高并发检索,并且都是毫秒级完成,数据量比较大时才几秒。为了提高检索能力,能够设计好你的key,用点作分隔符设计一个树型key,好比user.10010.name,而后用user.*.name来检索。
传统关系化结构数据如何转换设计成CoolHash的树型key/value结构,能够参考下面这个图:
除外还有key指针的设计去解决join关联的问题,CoolHash的不少特性都是其余k/v nosql数据库没有的,都来源于做者长期工做实践中的经验总结,一个追求创新的数据库引擎老是会面临有人对它的各类质疑,技术上有争论才好,被各大公司都测过,吵过,质疑过,尝试过,反思过才是对一个开源软件最好的鞭策和发展。
回到生产场景上,若是仅仅是从技术上验证一个东西,实际上是简单的,能够先测试,再上poc项目,再上小型生产系统,能够先只作数据同步,再分担读写检索压力,运行稳定再上中型生产系统,这样一步步从小到大应用下去就很容易经过时间去检验一项技术。实际上,CoolHash在线上跑了几个月也从未出过问题,天天10-20G的数据写入(覆盖),增量2-3G,总体容量超过几百g,超出内存大小运行,一直很稳定。
CoolHash的并行处理究竟是多线程模式仍是多进程模式?是多进程模式,上面是CoolHash的并行架构示意图,每一个数据工人都是一个独立进程,多个jvm进程共同做业,这是由于对底层存储结构、内存、mmap等控制上,多线程操做容易出问题的,多进程更安全可靠。CoolHash是在单机上采用多进程并行模式,只有单机引擎能力上去了,总体分布式集群的能力才会提高。若是你须要基于CoolHash作分布式数据库,能够参考自带例子AsynClient.java提供的异步处理等功能支持。