首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Spark Streaming实时流处理学习——初识实时流处理

1. 初识实时流处理 1.1. 业务现状分析 统计主站每个(指定)课程访问的客户、地域信息分布地域:ip转换客户端:useragent获取如上两个操作:采用离线(Spark/MapReduce)的方式进行统计 实现步骤课程编号、IP信息、useragent进行相应的统计分析操作:MapReduce/Spark 项目架构日志收集:Flume离线分析:MapReduce/Spark统计结果图形化展示 问题1小时级别10分钟5分钟1分钟秒级别 基于Hadoop的实现方案存在的问题?如何解决????===> 实时流处理框架 1.2. 业务现状分析 实时流处理产生背景 时效性高数据量大 实时流处理概述 实时计算流式计算实时流式计算 离线计算与实时计算对比 数据来源离线:HDFS 历史数据 数据量比较大 实时:消息队列(Kafka),实时新增/修改记录过来的某一笔数据 处理过程离线:MapReduce:map + reduce 实时:Spark(DStream/SS) 处理速度离线:慢 实时:快速 进程离线:启动+销毁 实时:7*24 实时流处理框架对比 Apache Storm Apache Spark Streaming微批处理框架 IBM Stream Yahoo! S4 Linkin Kafka Flink 实时流处理架构与技术选型 实时流处理在企业中的应用 电信行业 短信发布用户流量使用情况,通话计费等场景(需要实时,流式处理)。 流量陷阱监控软件,实时流式监控流氓流量盗取软件。 电商行业 电商平台中的实时推荐系统,根据用户目前正在访问的资料,实时推荐相关产品链接,或者推广方案。

优秀的个人博客,低调大师

(四)Java并发学习笔记--线程不安全类与写法

常见线程不安全的类有哪些呢 下图中,我们只画出了最常见的几种情况,我们常见的Collections集合都是线程不安全的 StringBuilder-demo: @Slf4j public class StringExample1 { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; public static StringBuilder stringBuilder = new StringBuilder(); private static void update() { stringBuilder.append("1"); } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}",stringBuilder.length()); } } 我测试的时候输出为,4985(因为线程不安全,所以每次的输出可能是不同的),如果StringBuilder类为线程安全的话,输出应该为5000 StringBuffer-demo @Slf4j public class StringExample2 { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; public static StringBuffer stringBuffer = new StringBuffer(); private static void update() { stringBuffer.append("1"); } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}",stringBuffer.length()); } } 输出为5000,且多次测试结果均为5000,证明StringBuffer类是线程安全的,通过看StringBuffer的实现可发现,其所有的实现都是加了synchronized关键字的,虽然可以保证线程安全但是性能是有损耗的,这也证明了StringBuilder的存在价值,如果定义StringBuilder为局部变量时是没有线程安全问题的,这就用到了上篇博客我们讲的堆栈封闭原理 simpleDateFormat-demo1 @Slf4j public class DateFormatExample1 { private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; private static void update() { try { simpleDateFormat.parse("20180208"); } catch (ParseException e) { log.error("parse exception",e); } } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } } 运行结果如下: 因为simpleDateFormat为线程不安全的类,所以在多线程访问的时候出现了异常 simpleDateFormat-demo2: @Slf4j public class DateFormatExample2 { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; private static void update() { try { //用堆栈封闭的方式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); simpleDateFormat.parse("20180208"); } catch (ParseException e) { log.error("parse exception",e); } } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } } 此demo为demo1的改进版,将SimpleDateFormat声明为局部变量,运用了堆栈封闭的方式保证了线程安全,运行此demo是没有异常抛出的 jodatime-demo import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; @Slf4j public class DateFormatExample3 { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; private static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd"); private static void update(int i) { log.info("{},{}",i,DateTime.parse("20180208", dateTimeFormatter).toDate()); } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } } 此demo引用了joda.time包,保证了线程安全,在实际的开发中,我们更推荐做日期转换的时候使用此包,这种处理方法不仅能保证线程安全,而且还有其它的优势。我导入的包如下: <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.9</version> </dependency> 以下我们做ArrayList,HashMap,HashSet的实例演示,它们都是线程不安全的,还好我们一般都将它们定义为局部变量(堆栈封闭),如果我们将它们定义为成员变量或static修饰的变量,在多个线程同时访问的时候就很容易出问题。 ArrayList-demo @Slf4j public class ArrayListExample { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; //arraylist是线程不安全的 private static List<Integer> list = new ArrayList<>(); private static void update(int i) { list.add(i); } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", list.size()); } } 如果是线程安全的输出应该为5000,实际输出为4945,且每次运行输出的值可能不一样,所以它是线程不安全的 HashSet-demo @Slf4j public class HashSetExample { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; //HashSet是线程不安全的 private static Set<Integer> set = new HashSet<>(); private static void update(int i) { set.add(i); } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", set.size()); } } 输出为4985,是线程不安全的(线程安全的话输出为5000) HashMap-demo @Slf4j public class HashMapExample { //请求总数 public static int clientTotal = 5000; //同时并发执行的线程数 public static int threadTotal = 200; //HashMap是线程不安全的 private static Map<Integer,Integer> map = new HashMap<>(); private static void update(int i) { map.put(i,i); } public static void main(String[] args)throws Exception { //定义线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定义信号量 final Semaphore semaphore = new Semaphore(threadTotal); //定义计数器闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception",e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", map.size()); } } 输出为4886(且每次运行输出值可能不同),是线程不安全的(线程安全的话输出为5000) 线程不安全的写法 典型的线程不安全的写法是:先检查,再执行 if(condition(a)){handle(a);} 就算a是一个线程安全的类所对应的对象,对a的处理handle(a)也是原子性的,但由于这两步之间的不是原子性的也会引发线程安全问题,如A、B两个线程都通过了a的判断条件,A线程执行handle(a)之后,a已经不符合condition(a)的判断条件了,可是此时B线程仍然要执行handle(a),这就引发了线程安全问题。

优秀的个人博客,低调大师

Java 学习(28)---(线程的控制 / 生命周期 /解决安全问题)

线程的控制 休眠线程 public class ThreadSleep extends Thread { @Override publicvoid run() { for ( int x = 0; x < 100; x++) { System. out .println(getName() + ":" + x + ", 日 期 : " + newDate()); // 睡眠 // 困了,我稍微休息 1 秒钟try { Thread. sleep (1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } 加入线程 publicclass ThreadJoin extends Thread { @Override publicvoid run() { for ( int x = 0; x < 100; x++) { System. out .println(getName() + ":" + x); } } } ThreadJoin tj1 = new ThreadJoin(); ThreadJoin tj2 = new ThreadJoin(); ThreadJoin tj3 = new ThreadJoin(); tj1.setName(" 李渊 " ); tj2.setName(" 李世民 " ); tj3.setName(" 李元霸 " ); tj1.start(); try { // 李渊执行完,再执行其他两个 tj1.join(); } catch (InterruptedException e) { e.printStackTrace(); } tj2.start(); tj3.start(); 礼让线程 publicclass ThreadYield extends Thread { @Override publicvoid run() { for (int x = 0; x < 100; x++) { System. out .println(getName() + ":" + x); // 让其他线程先走 Thread. yield (); } } } 后台线程 ThreadDaemon td1 = new ThreadDaemon(); ThreadDaemon td2 = new ThreadDaemon(); td1.setName(" 关羽 " ); td2.setName(" 张飞 " ); // 设置守护线程,主线程结束后,守护线程也会结束 td1.setDaemon(true); td2.setDaemon(true); td1.start(); td2.start(); // 设 置 主 线 程 名 为 “ 刘 备 ” Thread.currentThread().setName(" 刘备 " ); for ( int x = 0; x < 5; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } 终止线程 public class ThreadStop extends Thread { @Override public void run() { System. out.println(" 开始执行: " +new Date()); // 我要休息 10 秒钟,亲,不要打扰我哦 try { Thread.sleep(10000); }catch(Interrupted Exception e) { // e.printStackTrace(); System.out.println( " 线程被终止了" ); } System. out .println(" 结束执行: " +new Date()); } } ThreadStop ts =new ThreadStop(); ts.start(); // 你超过三秒不醒过来,我就干死你 try { Thread.sleep(3000); // ts.stop(); ts.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } 线程的生命周期 多线程安全问题 判断一个程序是否有线程安全问题的依据 ) A:是否有多线程环境 B:是否有共享数据 C:是否有多条语句操作共享数据 同步解决线程安全问题 同步代码块 synchronized( 对象 ) { 需要被同步的代码 ; } 这里的锁对象可以是任意对象。 synchronized(d) { if(tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张 票 " ); } } 同步方法 把同步加在方法上。这里的锁对象是 this privatesynchronizedvoid sellTicket() { if(tickets > 0) { try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +" 正在出售第 " + (tickets--) + " 张 票 " ); } } 静态同步方法 把同步加在方法上。 这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象) private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch(InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) +" 张票 " ); } } 同步锁对象 // 定义票 private int tickets = 100; // 定义锁对象 private Lock lock =new ReentrantLock(); @Override public void run() { while (true) { try{ // 加锁 lock.lock(); if (tickets > 0) { try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) +" 张票 " ); } }finally{ // 释放锁 lock.unlock(); } } } 同步的好处 同步的出现解决了多线程的安全问题。 同步的弊端 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

优秀的个人博客,低调大师

深入理解JAVA虚拟机学习笔记(二)垃圾回收策略

上篇文章介绍了JVM内存模型的相关知识,其实还有些内容可以更深入的介绍下,比如运行时常量池的动态插入,直接内存等,后期抽空再完善下上篇博客,今天来介绍下JVM中的一些垃圾回收策略。 一、finailize()方法 在介绍GC策略前,先介绍下GC中的finailize方法。当对象没有任何引用的时候,通常这个对象会被回收掉,但如果我们想在对象被回收前进行一些操作,比如关闭一些资源,或者让这个对象复活,不让他被回收怎么办?这时候就要用到finailize方法了。finailize方法是Object类中定义的方法,意味着任何一个对象都有这个方法。但这个方法只会调用一次,如果把这个对象复活后再次让这个对象死亡,那第2次回收该对象的时候是不会调用finailize方法的,而且优先级比较低,并不能保证一定会被执行,因此不建议使用finalize方法。总结起来就是3个特性:①、GC之前被调用 。②、只会被调用一次。③、不可靠,不能保证被执行,不建议使用。关于finalize使用方法,参考如下代码: 1 public class FinalizeTest { 2 3 private static FinalizeTest test; 4 /** 5 * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M 6 * 7 * @param args 8 */ 9 public static void main(String[] args) { 10 //先对test对象赋值 11 test = new FinalizeTest(); 12 int _1m = 1024 * 1024; 13 //将test置为null,便于回收 14 test = null; 15 try { 16 System.gc(); 17 //模拟睡眠5s,finalize优先级较低,保证finalize能执行 18 Thread.sleep(5000); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 if (test != null) { 23 System.out.println("first,i am alive"); 24 }else{ 25 System.out.println("first,i am dead"); 26 } 27 //由于test在finalize方法里复活了,再次将test置为null 28 test = null; 29 try { 30 System.gc(); 31 Thread.sleep(5000);//模拟睡眠5s,让GC回收 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 if (test != null) { 36 System.out.println("second,i am alive"); 37 }else{ 38 System.out.println("second,i am dead"); 39 } 40 41 } 42 @Override 43 protected void finalize() throws Throwable { 44 test = this ; 45 System.out.println("finalize excuted"); 46 super.finalize(); //调用父类的finailize方法 47 } 48 } 该代码运行结果如下: 可以看到,finalize方法执行后,test对象又被重新激活了,因此打印了first,i am alive。但是第二次GC的时候,finalize方法并未被执行,因此打印了second,i am dead。前面提到finalize是优先级低不可靠的,那如果没有Thread.sleep(5000),再来看下代码和结果: 1 public class FinalizeTest { 2 3 private static FinalizeTest test; 4 /** 5 * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M 6 * 7 * @param args 8 */ 9 public static void main(String[] args) { 10 //先对test对象赋值 11 test = new FinalizeTest(); 12 int _1m = 1024 * 1024; 13 //将test置为null,便于回收 14 test = null; 15 try { 16 System.gc(); 17 //模拟睡眠5s,finalize优先级较低,保证finalize能执行 18 //不执行睡眠操作,Thread.sleep(5000); 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 if (test != null) { 23 System.out.println("first,i am alive"); 24 }else{ 25 System.out.println("first,i am dead"); 26 } 27 //由于test在finalize方法里复活了,再次将test置为null 28 test = null; 29 try { 30 System.gc(); 31 //不执行睡眠操作,Thread.sleep(5000);//模拟睡眠5s,让GC回收 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 if (test != null) { 36 System.out.println("second,i am alive"); 37 }else{ 38 System.out.println("second,i am dead"); 39 } 40 41 } 42 @Override 43 protected void finalize() throws Throwable { 44 test = this ; 45 System.out.println("finalize excuted"); 46 super.finalize(); //调用父类的finailize方法 47 } 48 } 运行结果如下: 这里可以很清楚地看到,finalize方法的优先级是比较低的。 关于这个例子的反思:这个例子中第一段代码是参考《深入理解java虚拟机》里的代码实现的,但是总感觉有2点疑问:为什么test对象是以static修饰的成员变量方式存在?如果是static修饰,那就是存在方法区了,而方法区的GC通常效果不太好的。另一个是以成员变量的方式存在,这样finalize回收的时候,体现不出是对当前对象本身的回收,所以感觉这个例子并不是很好。 二、引用计数法 引用计数法是一种比较早的GC回收算法,目前一般不采用,其主要思想是:每个对象都维持一个引用计数器,初始值为0,当一个对象被引用的时候,该对象的引用计数器就加1,当不被引用的时候,该对象的引用计数器就减1,如果一个对象的引用计数器变为了0,则该对象被认为是可以回收的。采用这种方式的优缺点都很明显,优点是实现简单,效率高,缺点是可能存在循环引用,导致内存溢出。 三、标记-清除法 标记-清除法按名字分为“标记”和“清除”2个阶段,其基本思想是:首先标记出所有存活的对象,标记完成后,统一清除所有需要被回收的对象。那怎么判断某个对象是可以回收的呢?GC时,从一系列GC Roots根节点开始遍历,遍历时走过的路径即称为引用链,如果一个对象和GC Roots没有任何引用链相关,那么这个对象就不可用,就会被判定为可回收,这种算法也叫根搜索算法。那么哪些对象可以成为GC Roots对象呢?在java语言里,可以作为GC Roots的对象包括下面4种: 虚拟机栈中的引用变量 方法区中的类静态属性引用的对象 方法区中的常量引用的对象 本地方法栈中JNI(即native方法)的引用的对象 标记-清除法的算法示意图如下: 注:本文的GC回收算法图片转自一个网友的文章(点这里),该网友的图片内容也与原著一致,只是颜色不同。 四、新生代的复制法 复制法的基本思想是:将内存分为大小相等的2块,每次只使用其中一块,GC时每次将所有存活的对象复制到另一块区域,然后清理该内存。 这几种都是方法区和栈中的引用对象。复制法的优点是:实现简单,回收速度快,且不会产生内存碎片。但由于每次只使用其中一块,导致内存利用率较低。复制算法的示意图如下: 现在的商业虚拟机都采用复制法来回收新生代,由于新生代的对象98%以上都是朝生夕死的,所以并不需要按照1:1来分配,而是将内存分为较大的Eden区和2块较小的Survivor区(通常Eden和Survivor区大小的比值为8:1:1,可以根据SurvivorRationJVM内存参数来设置比值),每次使用Eden区和其中一块Survivor区类分配对象,GC时,将Eden区和Survivor区中的存活对象复制到另一块Survivor区域,这样一来,内存利用率就高了,而且运行速度也很快。 五、老年代的标记-整理法 复制法在对象存活率较高时,回收效率就变低了,而在老年代中,大部分的对象都是存活期较高的对象,因此就不适宜采用复制法进行老年代的GC。根据老年代的特点,并结合标记-清除法的思路,于是提出了标记-整理法。其主要思路是:标记过程与标记-清除法一致,只是标记完成后,不直接对未存活进行清除,而是将所有存活的对象都向一端移动,然后清理掉端边界以外的所有内存区域。这种方法的优点是不会产生内存碎片。标记-整理法的算法示意图如下:

优秀的个人博客,低调大师

【翻译】Sklearn与TensorFlow机器学习实用指南 —— 附录 C、SVM 对偶问题

为了理解对偶性,你首先得理解拉格朗日乘子法。它基本思想是将一个有约束优化问题转化为一个无约束优化问题,其方法是将约束条件移动到目标函数中去。让我们看一个简单的例子,例如要找到合适的 x 和 y 使得函数 最小化,且其约束条件是一个等式约束。使用拉格朗日乘子法,我们首先定义一个函数,称为拉格朗日函数。每个约束条件(在这个例子中只有一个)与新的变量(称为拉格朗日乘数)相乘,作为原目标函数的减数。Joseph-Louis Lagrange 大牛证明了如果是原约束优化问题的解,那么一定存在一个,使得是拉格朗日函数的驻点(驻点指的是,在该点处,该函数所有的偏导数均为 0)。换句话说,我们可以计算拉格朗日函数关于以及的偏导数;然后我们可以找到那些偏导数均为 0 的驻点;最后原约束优化问题的解(如果存在)一定在这些驻点里面。 原文发布时间为:20

优秀的个人博客,低调大师

ElasticSearch_学习_01_单实例安装与分布式安装

一、前言 二、下载 1.下载地址 https://www.elastic.co/downloads/past-releases 三、单实例安装 直接解压,window下运行elasticsearch.bat 即可。 四、分布式安装 将下载的压缩文件解压成三份,分别重命名为: es-master 、es-slave1 、es-slave2 1.master配置 (1)修改master的 /config/elasticsearch.yml 文件 在文件结尾增加: # 为了解决es-head插件 js跨域 问题 http.cors.enabled: true http.cors.allow-origin: "*" # 设置集群名称 cluster.name: wali # 设置节点名称 node.name: master # 指定节点为master节点 node.master: true network.host: 127.0.0.1 (2)启动master节点(即运行elasticsearch.bat) 2.slave1 配置 (1)修改slave1的 /config/elasticsearch.yml 文件 在文件结尾增加: cluster.name: wali node.name: slave1 network.host: 127.0.0.1 http.port: 8280 # 指定master地址 discovery.zen.ping.unicast.hosts: ["127.0.0.1"] (2)启动master节点 3.slave2节点 (1)修改slave2的 /config/elasticsearch.yml 文件 在文件结尾增加: cluster.name: wali node.name: slave2 network.host: 127.0.0.1 http.port: 8000 # 指定master地址 discovery.zen.ping.unicast.hosts: ["127.0.0.1"] (2)启动master节点 五、安装elasticsearch-head 1.下载地址 https://github.com/mobz/elasticsearch-head 2.安装 将下载的文件解压,然后执行以下命令来下载依赖。(需要安装node.js或者yarn) npm install 或者 yarn install 3.启动 执行以下命令来启动elasticsearch-head npm run start 或者 yarn run start 3.管理页面 启动成功后,即可进入管理页面。管理页面地址为: http://localhost:9100/ 如下图,已成功开启了三个节点。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册