|
1.安装Apache HTTP server:http://httpd.apache.org/
2.安装2-3个(或更多)Tomcathttp://tomcat.apache.org/,安装zip版,因为安装多个Windows Service Installer版会出现错误(可以安装一个Installer版,其他两个用zip版)。
3.配置3个Tomcat,使得3个Tomcat在一台机器上可以同时运行:
修改三个Tomcat安装目录下的bin/startup.bat,将其中的CATALINA_HOME环境变量修改成互不相同的名字,比如CATALINA_HOME1,CATALINA_HOME2,CATALINA_HOME3。
4.配置集群
1) 修改Apache安装目录下的conf/httpd.conf文件,在文件末尾加入如下几行ProxyRequests Off <proxy balancer://cluster> BalancerMember ajp://127.0.0.1:8009 loadfactor=1 route=jvm1BalancerMember ajp://127.0.0.1:9009 loadfactor=1 route=jvm2BalancerMember ajp://127.0.0.1:9099 loadfactor=1 route=jvm3</proxy>8009,9009,9099分别是三个Apache用来于Tomcat连接的端口oadfactor是指每一个tomcat的负载系数。
2) 修改Tomcat下的conf/server.xml
a.将所有3个Tomcat的server.xml中的
<Engine name="Catalina" defaultHost="localhost">
修改为<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">,3个tomcat的jvmRoute分别为jvm1,jvm2,jvm3
b.修改所有3个server.xml中的<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />,将8009端口改为与上面Apache中配置的三个端口一致(这点很重要!),与上面配置的jvm1,jvm2也要一致。也就是说,配置为jvm1的,这里端口改为8009,配置为jvm2的tomcat,这里端口给为9009,jvm3的为9099。
c.修改server.xml中的所有其他端口,使得3个tomcat没有重复的端口,包括:<Server port="8005",<Connector port="8080",redirectPort="8443" 这三个,三个tomcat的这三个端口都要不一样,其中每个tomcat中有两个redirectPort,同一个tomcat中的redirectPort一样,不同tomcat中的redirectPort不一样。
4.现在,集群就应该已经正确的构建完毕,访问Apache(localhost,端口为80)时,Apache就会将请求转发给这3个tomcat中的一个,可以自己写一个JSP或者servlet试试,注意,三个tomcat中的webapp下面都需要有一份JSP/servlet。
5.写一个实验程序(servlet),发布到3个tomcat上,写一个客户端程序,多线程并发访问Apache,观察三个tomcat的负载均衡情况(可以调节一下loadfactor再观察),并绘制在线程越来越多的情况下,响应时间曲线。
由于规模较小的计算,响应时间非常快,可以忽略。所以选择一个计算量较大的运算:判断一个数是否为素数,Sevlet代码如下:package com.hw;import java.io.IOException;import java.math.BigDecimal;import java.math.BigInteger;import java.math.MathContext;import java.math.RoundingMode;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** Servlet implementation class JudgePrimeServlet*/public class JudgePrimeServlet extends HttpServlet {private static final long serialVersionUID = 1L;private static final String TRUE_JSON = "{success:true}";private static final String FALSE_JSON = "{success:false}";public JudgePrimeServlet() {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String numStr = request.getParameter("number");boolean ans;if(numStr.length() < 10)ans = isPrime(Long.parseLong(numStr));elseans = isPrime(new BigInteger(numStr));System.out.println(numStr + " : " + ans);response.getWriter().write(ans ? TRUE_JSON : FALSE_JSON);response.getWriter().flush();response.getWriter().close();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}public static boolean isPrime(long n){if(n % 2 == 0){if(n == 2)return true;return false;}long up = (long)Math.sqrt((double)n);for(int i = 3; i <= up; i += 2)if(n % i == 0)return false;return true;}public static boolean isPrime(BigInteger n){if(n.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)){if(n.equals(BigInteger.valueOf(2)))return true;return false;}MathContext mc = new MathContext(n.toString().length(), RoundingMode.HALF_DOWN);BigInteger up = new BigDecimal(Math.sqrt(n.doubleValue()) ,mc).toBigInteger();for(BigInteger i = BigInteger.valueOf(3); i.compareTo(up) <= 0; i = i.add(BigInteger.valueOf(2)))if(n.mod(i).equals(BigInteger.ZERO))return false;return true;}},客户端的线程代码如下:public class ClientTestThread extends Thread{public static final long[] primeArr = new long[] { 2055437, 2057317, 5298991, 5300467, 5352869, 5377679, 6220229,7155887, 8491247, 8885837, 9999929, 9999931, 9999943, 9999971, 9999973, 9999991, 11547391, 12531809,13192643, 15766453, 16854379, 26459779, 26456789, 26453803, 29999791, 1000003871, 1015490783, 1800000011,1800000019, 1800000047, 1800000049, 1800000053, 1800000061, 1800000109, 1800000113, 1800001523, 1978012607,1978012609, 1978012633, 1978012669, 1978012703, 1978012709, 1978012739, 1978012741, 1978012759, 1978012763,2008693679, 2008693681, 2008693727, 2008693741, 2008693759, 2095462079, 2095462099, 2095462151, 2095462163,2095462207, 2099999999 };private static Long timer = 0L;@Overridepublic void run(){URL url;HttpURLConnection conn;long millisec = GregorianCalendar.getInstance().getTimeInMillis();try{url = new URL("http://localhost/ClusterExp/JudgePrimeServlet?number=" + 2099999999);conn = (HttpURLConnection) url.openConnection();Scanner scan = new Scanner(conn.getInputStream());if(scan.hasNext())scan.nextLine();scan.close();ClientTestThread.addToTimer((GregorianCalendar.getInstance().getTimeInMillis() - millisec));}catch (MalformedURLException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();}}public static void addToTimer(long time){synchronized (timer){timer += time;}}public static void clearTimer(){synchronized (timer){timer = 0L;}}public static Long getTimer(){return timer;}},客户端界面以及生成多线程、绘制响应时间曲线代码如下(使用SWT,如果要运行,需要使用eclipse.org的SWT包):package com.hw.client;import org.eclipse.swt.SWT;public class TestClient{protected Shell shell;private Text lowField;private Text highField;private Group lineGroup;private static final int unit = 10;private static final int off = 10;private static final int width = 800;private static final int height = 600;/*** Launch the application.* * @param args*/public static void main(String[] args){try{TestClient window = new TestClient();window.open();}catch (Exception e){e.printStackTrace();}}/*** Open the window.*/public void open(){Display display = Display.getDefault();createContents();shell.open();shell.layout();while (!shell.isDisposed()){if (!display.readAndDispatch()){display.sleep();}}}/*** Create contents of the window.*/protected void createContents(){shell = new Shell();shell.setSize(1024, 768);shell.setText("/u8D1F/u8F7D/u5E73/u8861/u6D4B/u8BD5/u5BA2/u6237/u7AEF");shell.setLayout(null);Composite composite = new Composite(shell, SWT.NONE);composite.setBounds(10, 10, 655, 97);Group group = new Group(composite, SWT.NONE);group.setBounds(10, 23, 422, 64);group.setText("/u6D4B/u8BD5/u7684/u7EBF/u7A0B/u6570/u91CF/u533A/u95F4");group.setLayout(null);Label label = new Label(group, SWT.NONE);label.setBounds(10, 27, 60, 12);label.setText("/u4E0B/u9650");lowField = new Text(group, SWT.BORDER);lowField.setBounds(76, 24, 106, 18);Label label_1 = new Label(group, SWT.NONE);label_1.setBounds(198, 27, 60, 12);label_1.setText("/u4E0A/u9650");highField = new Text(group, SWT.BORDER);highField.setBounds(265, 24, 106, 18);Button button = new Button(composite, SWT.NONE);button.addSelectionListener(new SelectionAdapter() {@Overridepublic void widgetSelected(SelectionEvent arg0) {GC gc = new GC(lineGroup);gc.setForeground(new Color(Display.getCurrent(), 255, 0, 0));gc.drawLine(off, height - off, width + off, height - off);gc.drawLine(off, height - off, off, off);for(int i = 1; i < width / unit; ++ i){if( i % 5 == 0)gc.drawString(String.valueOf(i), i * unit + off - 2, height - off + 3);}gc.drawString("线程数", width + off, height - off - 10);gc.setBackground(new Color(Display.getCurrent(), 255, 0, 0));for(int i = 1; i < width / unit; ++ i){gc.fillRectangle(i * unit + off, height - off - 3, 2, 3);}for(int i = 1; i < height / unit; ++ i){gc.fillRectangle(off, height - off - i * unit, 3, 2);}int low = Integer.parseInt(lowField.getText());int high = Integer.parseInt(highField.getText());int lastX = off, lastY = height - off;int x, y;for (int i = low; i <= high; ++i){Thread[] multiThread = new ClientTestThread;for (Thread t : multiThread){t = new ClientTestThread();t.start();}boolean allFinished = false;while (!allFinished){allFinished = true;for (Thread t : multiThread){if (t != null && t.isAlive()){allFinished = false;Thread.yield();break;}}}x = i * unit + off;y = height - off - ClientTestThread.getTimer().intValue() / i / 3;if(y < 0)y = 0;gc.drawLine(lastX, lastY, x, y);System.out.println(x + "," + y);lastX = x;lastY =y;//gc.fillOval(i, 600 - ClientTestThread.getTimer().intValue(), 3,3);// gc.drawPoint(i, ClientTestThread.getTimer().intValue());ClientTestThread.clearTimer();}}});button.addMouseListener(new MouseAdapter(){@Overridepublic void mouseDown(MouseEvent arg0){}});button.setBounds(476, 53, 72, 22);button.setText("/u6D4B/u8BD5");lineGroup = new Group(shell, SWT.NONE);lineGroup.setText("/u8D1F/u8F7D/u66F2/u7EBF");lineGroup.setBounds(10, 113, 996, 618);}},运行后,三个tomcat的控制台都会输出结果,说明请求被分发给三个tomcat,运行1-75个线程的响应时间曲线如下:
|
|