MQTT Client Library Enyclopedia – Paho Android Service

原文:http://www.hivemq.com/blog/mqtt-client-library-enyclopedia-paho-android-service

Guest post by Sandro Kock

Pahao Android Service
Language Java
License Eclipse Public License v1.0 and Eclipse Distribution License v1.0
Website https://eclipse.org/paho/clients/android/
API Style Asynchronous

Description

The Paho Android Service is an interface to the Paho Java MQTT Client library for the Android Platform. The MQTT connection is encapsulated within an Android-Service that runs in the background of the Android application, keeping it alive when the Android application is switching between different Activities. This layer of abstraction is needed to be able to receive MQTT messages reliably. As the Paho Android Service is based on the Paho Java client library it can be considered stable and used in production. The project is actively maintained by the Eclipse Paho project.

Features

MQTT 3.1 ok
MQTT 3.1.1 ok
LWT ok
SSL/TLS nok
Automatic Reconnect nok (On the road map)
QoS 0 ok
QoS 1 ok
QoS 2 ok
Authentication ok
Throttling nok

Usage

Installation

Android uses Gradle as a build system and dependency management, therefor this blog post describes how the Paho Android Service can be added to an application via Gradle. The most convenient way to start a new Android Application is to use Android Studio. To add the Paho Android Service as a dependency to you app add the following parts to your gradle file.

The first part adds the Paho release repository to the gradle config, so that Gradle is able to find the packaged Paho Android Service JAR. The second part adds the Paho Android Service as a dependency to the application. The exclusion of the Android Support library exclude module: 'support-v4' is only necessary if the Android application is using the Android Support Library to backport newer Android features to older Android versions. To have the latest Snapshot release within your application the gradle config below can be used.

Connect

As already mentioned, the Paho Android Service encapsulates the MQTT connection and offers an API for that. To be able to create a binding to the Paho Android Service, the service needs to be declared in theAndroidManifest.xml. Add the following within the <application> tag:

The Paho Android Service needs the following permissions to work:

Add those to the <manifest> tag.

Usually an Android Activity requests or binds to an Android Service to use it, for e.g. the LocationManager to receive updates when the GPS position of the user changes. The Paho Android Service is not meant to bind to directly. Instead the provided MqttAndroidClient client interface binds to the service once created. To create and establish an MQTT-connection use the following code snipped:

In the first line a helper Function of the Paho MQTT client is used to generate a random user id. The second line creates an instance of an Android MQTT client, that will bind to the Paho Android Service. By calling the connectmethod of the MqttAndroidClient the client will asynchronously try to connect to the MQTT broker and return a token. That token can be used to register callbacks, to get notified when either the MQTT-connection gets connected or an error occurs. Running the above example inside an Android Activity.onCreate method will print “onSuccess” or “onFailure” to the console.

Connect with MQTT 3.1 or MQTT 3.1.1

The MqttAndroidClient will connect with MQTT 3.1.1 by default, with a fallback to 3.1. To intentionally connect with MQTT 3.1 a MqttConnectOptions object can be supplied to the connect method:

Connect with LWT

Like the MQTT version, the Last Will And Testament (LWT) can be added into the MqttConnectOptions object.

Besides the payload of the LWT, everything is straight forward and can be just set. Many MQTT clients assume that the payload is an UTF-8 formatted string and convert the payload automatically. The fact that MQTT is a binary protocol is often hidden with that. By calling String#getBytes the string will be encoded with the systems default charset (UTF-8 on Android).

Connect with Username / Password

Again like the MQTT version and the LWT, the username and password can be supplied within the options object.

Publish

The MqttAndroidClient allows messages to be published via its publish(topic, MqttMessage) method. By design the MqttAndroidClient dose not queue any messages if the client is not connected and will throw an error when trying to send messages when the client is offline client.isConnected() == false. After the first connect, the IMqttActionListener.onSuccess method is called when a MQTT connection is established successfully.

Publish a retained message

To send a retained MQTT message the MqttMessage.retained attribute can be set to true viaMqttMessage.setRetained(true).

Subscribe

Subscriptions can be created via the MqttAndroidClient.subscribe method, which takes the topic and the QOS as parameters and returns a IMqttToken. The token can be used to keep track if the subscription can successfully established or failed. The example below subscribes to the topic “foo/bar” with QOS 1

Unsubscribe

Disconnect

To disconnect the client call the disconnect method of the MqttAndroidClient object. The example below saves the token returned by the disconnect method and adds a IMqttActionListener to get notified when the client is successfully disconnected.

Using SSL / TLS

When connecting with SSL/TLS the MQTT-broker has to use a valid certificate that is trusted via the chain of trust of the Android device or provide a custom Java SocketFactory. Currently I am not aware of any public MQTT broker that can be used to test a SSL/TLS connection without a custom SocketFactory, hopefully this will change in the near feature with Let’s Encrypt in place.

IoT Eclipse provides an MQTT Sandbox running MQTT encrypted on iot.eclipse.org:8883 and supports TLS 1.0, 1.1 and 1.2. Android on the other hand uses a cryptography API library called BouncyCastle. To generate a BouncyCastle keystore (BKS) on a development machine the BounceCastleProvider class is required in the JAVA-Classpath. The JAR containing the class can be downloaded here. To generate the BKS the JDK keytool can be used with the following parameters:

The command assumes that you saved the BouncyCastle JAR and the iot.eclipse.org.crt into the current directory. It will generate a BouncyCastle Keystore names iot.eclipse.org.bks with the password set to eclipse-password.

To actually use the keystore, create a folder named “assets” in the “src/main” directory of you app and copy theiot.eclipse.org.bks file into it. The following example will create a secure MQTT connection to the Eclipse test broker:

The example uses the utility function getSSLSocketFactory of the MqttAndroidClient to create a customSocketFactory from the BKS keystore input stream.

Full example application

The Eclipse Paho project provides a very detailed example application that demonstrates the capabilities of the Paho Android Service. A packaged application is available at Paho Android Sample. The APK is based on the current development branch in the Eclipse repository. To clone the entire GIT repository use the following command:

The Android sample application source is located in theorg.eclipse.paho.android.service/org.eclipse.paho.android.sample folder, that can be opened with Android Studio.

发表在 Linux | 留下评论

给Android Studio设置代理

原文:http://blog.csdn.net/lchad/article/details/43567675

我们都知道Android Studio是基于JetBrains公司的IDEA开发的,而我们写的每一个程序又都是由Gradle构建的,Gradle集合了Ant和Maven的优点,又解决了他们的缺点,但是它有一个特点还是值得我们注意的.我们每一次点击这个按钮来执行我们的程序时,都会先调用这个来进行构建,这个和Eclipse上还是不一样的,因为Gradle构建的时候要联网,但是联网就联网呗,偏偏还要连接到墙外面的网络,我当初刚开始折腾Android开发的时候可被它给坑苦了,现在想一想真是蛋疼啊,信心满满的装好了高大上的Android Studio,但是由于对它不够了解,且没有深刻理解付费科学上网的重要性,时常出现Gradle Sync Failed的错误,弄得我在Ubuntu和Windows上来回折腾了好几回,一直以为是自己的系统有问题,直到后来(我终于学会了如何去爱大笑).这真的是一个大坑,设想一下,如果我当初稍微不坚定一点,那么可能就跟Android开发Say GoodBye了.所以才有了写下这篇博客的念头,希望这之后的新人们能少踩一些坑(诶,好像我到现在也只是一个新人啊).

作为一个天朝的Android程序员,如果要是不会科学上网的话,那是不是有点太逊了.先说说我吧.第一次跳出墙是刚上大二的时候,偶然间听说了一个叫做Go Agent的开源软件,能免费FQ,所以我在折腾了两个多小时之后终于体会了一把什么叫外面的世界,当时还截了几张YouTube和FaceBook的图发在QQ空间上(后来觉得比较二逼就删掉了),当时还真的是挺兴奋的.后来知道了Go Agent是由Python语言编写的,并且很多人似乎对这门语言很推崇,我就特意去图书馆借了本Python核心编程翻了翻.算是对Go Agent的致敬吧.至于如何使用Go Agent我在这里就不介绍了,大家有兴趣的话可以找一篇帖子试一下.

现在已经不用GoAgent,因为最近GFW屏蔽的比较严重了,Go Agent十分的不稳定,总是需要更换IP List,所以转战到ShadowSocks了.中文名叫做影梭,就是它.

好了,扯得好像有点远了,快点进入正题吧.

先打开我们的Android Studio,点击工具栏的file下的settings,如下图

之后再搜索框上面输入Proxy,然后按第四步提示点击,如下图

之后就进入了设置代理的界面了,如下图

默认情况下,No Proxy是被选中的,意思是不需要设置代理.如果你用的是ShadowSocks代理的话则可以按照下面的5 6 7 8四步来做,如下图:

这里稍微解释一下,

  • Manual proxy configuration翻译过来是人工设置代理的意思.
  • ShadowSocks是SOCKS代理方式
  • 127.0.0.1的意思是用你本机做代理
  • 1080是ShadowSocks默认的端口号
这时候如果你的ShadowSocks是能正常工作的话,那么就可以实现Android Studio上网了.测试一下,点击工具栏的Help下的Check for Update选项,如果没有提示不能联网或者提示你更新Studio的话,就说明你成功了少年.
最后,如果你用的是GoAgent的话,只需要把端口号修改为8087就可以了,其他任何一步都不需要改变,至于其他的VPN的话,请参考自己的软件进行设置吧.
发表在 android | 留下评论

Android ConstraintLayout详解

原文链接:https://codelabs.developers.google.com/codelabs/constraint-layout/#0

1. Overview

In this codelab, you’ll learn about ConstraintLayout—a new type of layout available in the Android Support repository built on top of a flexible constraint system. By the end of this codelab, you’ll be able to play with the layout editor in Android Studio and build a relatively complex layout.

What you’ll learn

  • The Constraint System used by the new layout manager.
  • Creating constraints to build flexible and efficient layouts.
  • The various features of the new layout editor.

What you’ll need

2. Get the sample code

To download the sample code, you can either:

DOWNLOAD ZIP

…or clone the GitHub repository from the command line by using the following command:

$ git clone https://github.com/googlecodelabs/constraint-layout.git

8. Using Autoconnect to create constraints

Autoconnect, as the name suggests, automatically creates connections between widgets. It’s important to understand that the Autoconnect feature tries to create connections to the neighboring widgets.

Before we get started with this section, ensure that:

  1. Open res/layout/activity_main_autoconnect.xml from the Project pane. Ensure that you select the “Design” tab.
  2. Autoconnect is enabled

Next we select the ImageView and center it in the layout by dragging it until the guidelines are shown. A couple of seconds after it is centered, autoconnect kicks in and creates constraints with the top, left, bottom and right of the container, as shown in the animation below.

Here we have a single ImageView on the layout and we see how Autoconnect creates the constraints.

Here are the steps for the next part of this section. For guidance, the animation above shows the steps used below:

  1. Align the ImageView to be placed at the top and use the Inspector (AnySize) to ensure that it expands to fill the width of the parent.
  2. Place two buttons at the bottom right corner of the layout. Use the Inspector pane to change the text attribute of the rightmost button to @string/upload and the one to the left of it to @string/discard.
  3. Drag a TextView and a Plain Text from the palette and place them on the layout.
  4. Adjust the TextView and Plain Text field to be 48dp apart. In a few seconds, Autoconnect creates the constraints to the widgets.
  5. Similarly select the upload button and place it close to our right margin and we let Autoconnect do the rest.
  6. Lastly place the discard button 32dp away from the upload button.

As an exercise, also move the TextView 48dp below the ImageView. To do this select the TextView and move until it’s 48dp below the ImageView.

It’s important to understand that Autoconnect only creates constraints for the widget being currently moved.

Autoconnect aids you by connecting to the nearest widgets which is helpful in many situations. There are cases where Autoconnect does not achieve the desired behavior, and developers should either use manual constraints or Inference to build their ConstraintLayout. Inference will be discussed in the next step of the codelab.

9. Using Inference to create constraints

The Inference engine aids developers by creating constraints among elements added in the layout. The constraints created by Inference depend on the types of elements added to the layout and their sizes.

Setup

For this step, we start with the layout/activity_main_inference.xml layout. Open the layout file in the Design view. By default, the layout in this file defines the following:

  • ImageViews for the @drawable/singapore and @drawable/ic_star. The ic_star image has already been constrained to have a vertical bias at 81%. You can view the vertical bias of the ImageView containingic_star by selecting it and checking the Inspector as discussed before.
  • The large ImageView’s bottom anchor (@drawable/singapore) is constrained to the ic_star ImageView’s bottom anchor with a margin of 16dp.
  • In addition to the ImageView, there are TextViews for Camera, Settings, and the subtitle for the ImageView.

What you’ll learn

  • Expanding a view horizontally and vertically using actions on the menu.
  • Using the Inference button to aid in creating constraints using inference.

Understand the UI Builder icon actions

Since we’ll be using some of these options, this is a good time to look at the actions available on the UI Builder.

Delete all constraints. This is helpful when you want to redo all the constraints in your layout in a different way.

Create constraints using inference. The inference engine tries to find and create optimal connections based on various factors such as the positions of the widgets and their size.

Expands the widget horizontally to satisfy constraints.

Expand the widget vertically to satisfy constraints.

Adding a TextView that occupies available space

Our goal is to add a TextView for the description of the image. We already have a@string/singapore_description which spans multiple lines.

  1. First, drag a TextView from the palette and place it below the settings text view.
  2. Use the action to expand the view horizontally to match guidelines.
  3. Use the action to expand vertically to fill available vertical space.

Using the Inference action

Now that you have the TextView in the layout, you are ready to see Inference in action.

Click the infer constraintsaction to create constraints using Inference.

The inference engine creates constraints among all the views in the layout. Your final layout should look like the following:

Once the constraints are created, you can modify the “virtual device to render with” by clicking on the button at the top left of the UI Builder. Choose a different device such as Nexus 6P or Nexus 9 to see that the layout renders correctly.

You’ve now seen the entire spectrum of using the constraint system: creating manual constraints, constraints using auto-connect, and constraints using the Inference engine.

Auto-connect and Inference aid you by having the layout engine figure out how to create constraints for various elements of your UI. You are then free to further modify the constraints created either by Auto-connect or the Inference engine as you see fit.

What we’ve covered

  • Creating Manual constraints
  • Creating constraints using Autoconnect.
  • Creating constraints using Inference.
发表在 android | 留下评论

AndroidStudioでアプリをビルドしたときに「Plugin is too old, please update to a more recent version」エラーが出た時の対処法

Problem

AndroidStudioでアプリをビルドしたときに、以下のエラーが発生する。

Error:(21, 0) Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRIDE environment variable to "41b72d353033bfb5aa4d6a98088a908dcae15ef9"

Solution

1 . ターミナルで、以下のコマンドを実行し環境変数を登録する
(OS Xアプリケーションに環境変数を渡すには、launchctlコマンドのsetenvオプションで設定します。アプリケーションの再起動後から設定が反映されます。)

$ launchctl setenv ANDROID_DAILY_OVERRIDE 41b72d353033bfb5aa4d6a98088a908dcae15ef9

2 . AndroidStudioを起動して、アプリをビルドする。

参考

发表在 Linux | 留下评论

http反向代理之haproxy详解

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://freeloda.blog.51cto.com/2033581/1294094

大纲

一、前言

二、haproxy 简介

三、haproxy 版本特性

四、haproxy 支持的平台及OS

五、haproxy 性能特点

六、负载均衡器的性能评估因素

七、haproxy 配置文件详解

八、安装与配置haproxy

九、haproxy 案例演示

十、haproxy 配置文件中的关键字参考

十一、haproxy 监控功能详解

十二、haproxy 负载均衡MySQL服务的配置示例

一、前言

在上几篇博客中我们主要讲解了nginx的相关知识,有nginx作为Web服务器的配置讲解,作为反向代理、负载均衡服务器的讲解,在这一节中我们主要讲解有haproxy知识,haproxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤其适用于高负载且需要持久连接或7层处理机制的web站点。下面我们就来详细的说一说haproxy。

二、haproxy 简介

HAProxy是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,HAProxy是完全免费的、借助HAProxy可以快速并且可靠的提供基于TCP和HTTP应用的代理解决方案。

  • 免费开源,稳定性也是非常好,这个可通过一些项目可以看出来,单Haproxy也跑得不错,稳定性可以与硬件级的F5相媲美;
  • 根据官方文档,HAProxy可以跑满10Gbps-New benchmark of HAProxy at 10 Gbps using Myricom’s 10GbE NICs (Myri-10G PCI-Express),这个数值作为软件级负载均衡器是相当惊人的。官方测试的性能情况如下图,
  • bench

  • HAProxy 支持连接拒绝 : 因为维护一个连接的打开的开销是很低的,有时我们很需要限制攻击蠕虫(attack bots),也就是说限制它们的连接打开从而限制它们的危害。 这个已经为一个陷于小型DDoS攻击的网站开发了而且已经拯救了很多站点,这个优点也是其它负载均衡器没有的。
  • HAProxy 支持全透明代理(已具备硬件防火墙的典型特点): 可以用客户端IP地址或者任何其他地址来连接后端服务器. 这个特性仅在Linux 2.4/2.6内核打了cttproxy补丁后才可以使用. 这个特性也使得为某特殊服务器处理部分流量同时又不修改服务器的地址成为可能。
  • HAProxy现多于线上的Mysql集群环境,我们常用于它作为MySQL(读)负载均衡。
  • 自带强大的监控服务器状态的页面,实际环境中我们结合Nagios进行邮件或短信报警,这个也是我非常喜欢它的原因之一
  • HAProxy支持虚拟主机。
  • HAProxy特别适用于那些负载特大的web站点, 这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。

haproxy-pmode

注,在功能上,能以proxy反向代理方式实现Web均衡负载,这样的产品有很多。包括lvs,Nginx,ApacheProxy,lighttpd等。国内生产环境上使用Haproxy的公司很多,例如淘宝的CDN系统,

taobao

三、haproxy 版本特性

HAProxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤其适用于高负载且需要持久连接或7层处理机制的web站点。

1.HAProxy目前主要有两个版本:

  • 1.4——提供较好的弹性:衍生于1.2版本,并提供了额外的新特性,其中大多数是期待已久的。
  • 1.3——内容交换和超强负载:衍生于1.2版本,并提供了额外的新特性。

2.haproxy 1.4 版本特性

  • 客户端的长连接(client-side keep-alive)
  • TCP加速(TCP speedups)
  • 响应池(response buffering)
  • RDP协议
  • 基于源的粘性(source-based stickiness)
  • 更好的统计数据接口(a much better stats interfaces)
  • 更详细的健康状态检测机制(more verbose health checks)
  • 基于流量的健康评估机制(traffic-based health)
  • 支持HTTP认证
  • 服务器管理命令行接口(server management from the CLI)
  • 基于ACL的持久性(ACL-based persistence)
  • 日志分析器

注,更多特性请查看官方文档:http://haproxy.1wt.eu/#news

3.haproxy 1.3 版本特性

  • 内容交换(content switching):基于任何请求标准挑选服务器池
  • ACL:编写内容交换规则
  • 负载均衡算法(load-balancing algorithms):更多的算法支持
  • 内容探测(content inspection):阻止非授权协议
  • 透明代理(transparent proxy):在Linux系统上允许使用客户端IP直接连入服务器
  • 内核TCP拼接(kernel TCP splicing):无copy方式在客户端和服务端之间转发数据以实现数G级别的数据速率
  • 分层设计(layered design):分别实现套接字、TCP、HTTP处理以提供更好的健壮性、更快的处理机制及便捷的演进能力
  • 快速、公平调度器(fast and fair scheduler):为某些任务指定优先级可实现理好的QoS
  • 会话速率限制(session rate limiting):适用于托管环境

注,一般企业中用的较多的还是haproxy 1.4,但应用还是得看实际情况。

四、haproxy 支持的平台及OS

  • x86、x86_64、Alpha、SPARC、MIPS及PARISC平台上的Linux 2.4;
  • x86、x86_64、ARM (ixp425)及PPC64平台上的Linux2.6;
  • UltraSPARC 2和3上的Sloaris 8/9;
  • Opteron和UltraSPARC平台上的Solaris 10;
  • x86平台上的FreeBSD 4.1-8;
  • i386, amd64, macppc, alpha, sparc64和VAX平台上的OpenBSD 3.1-current;

注,若要获得最高性能,需要在Linux 2.6或打了epoll补丁的Linux 2.4上运行haproxy 1.2.5以上的版本。haproxy 1.1l默认使用的polling系统为select(),其处理的文件数达数千个时性能便会急剧下降。1.2和1.3版本默认的为poll(),在有些操作系统上可会也会有性能方面的问题,但在Solaris上表现相当不错。HAProxy 1.3在Linux 2.6及打了epoll补丁的Linux 2.4上默认使用epoll,在FreeBSD上使用kqueue,这两种机制在任何负载上都能提供恒定的性能表现。在较新版本的Linux 2.6(>=2.6.27.19)上,HAProxy还能够使用splice()系统调用在接口间无复制地转发任何数据,这甚至可以达到10Gbps的性能。

总结:

基于以上事实,在x86或x86_64平台上,要获取最好性能的负载均衡器,建议按顺序考虑以下方案。

  • Linux 2.6.32及之后版本上运行HAProxy 1.4;
  • 打了epoll补丁的Linux 2.4上运行HAProxy 1.4;
  • FreeBSD上运行HAProxy 1.4;
  • Solaris 10上运行HAProxy 1.4;

五、haproxy 性能特点

HAProxy借助于OS上几种常见的技术来实现性能的最大化。

  • 单进程、事件驱动模型显著降低了上下文切换的开销及内存占用。
  • O(1)事件检查器(event checker)允许其在高并发连接中对任何连接的任何事件实现即时探测。
  • 在任何可用的情况下,单缓冲(single buffering)机制能以不复制任何数据的方式完成读写操作,这会节约大量的CPU时钟周期及内存带宽;
  • 借助于Linux 2.6 (>= 2.6.27.19)上的splice()系统调用,HAProxy可以实现零复制转发(Zero-copy forwarding),在Linux 3.5及以上的OS中还可以实现零复制启动(zero-starting);
  • MRU内存分配器在固定大小的内存池中可实现即时内存分配,这能够显著减少创建一个会话的时长;
  • 树型存储:侧重于使用作者多年前开发的弹性二叉树,实现了以O(log(N))的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列;
  • 优化的HTTP首部分析:优化的首部分析功能避免了在HTTP首部分析过程中重读任何内存区域;
  • 精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等;

所有的这些细微之处的优化实现了在中等规模负载之上依然有着相当低的CPU负载,甚至于在非常高的负载场景中,5%的用户空间占用率和95%的系统空间占用率也是非常普遍的现象,这意味着HAProxy进程消耗比系统空间消耗低20倍以上。因此,对OS进行性能调优是非常重要的。即使用户空间的占用率提高一倍,其CPU占用率也仅为10%,这也解释了为何7层处理对性能影响有限这一现象。由此,在高端系统上HAProxy的7层性能可轻易超过硬件负载均衡设备。

在生产环境中,在7层处理上使用HAProxy作为昂贵的高端硬件负载均衡设备故障故障时的紧急解决方案也时长可见。硬件负载均衡设备在“报文”级别处理请求,这在支持跨报文请求(request across multiple packets)有着较高的难度,并且它们不缓冲任何数据,因此有着较长的响应时间。对应地,软件负载均衡设备使用TCP缓冲,可建立极长的请求,且有着较大的响应时间。

六、负载均衡器的性能评估因素

三个重要因素:

  • 会话率 :单位时间内的处理的请求数
  • 会话并发能力:并发处理能力
  • 数据率:处理数据能力

经过官方测试统计,haproxy  单位时间处理的最大请求数为20000个,可以同时维护40000-50000个并发连接,最大数据处理能力为10Gbps。综合上述,haproxy是性能优越的负载均衡、反向代理服务器。好了,下面我们来说说haproxy的配置文件。

七、haproxy 配置文件详解

官方配置

1.配置文件的格式

HAProxy的配置处理3类来主要参数来源:

  • 最优先处理的命令行参数;
  • “global”配置段,用于设定全局配置参数;
  • proxy相关配置段,如“defaults”、“listen”、“frontend”和“backend”;

2.支持的时间格式

一些包含了值的参数表示时间,如超时时长。这些值一般以毫秒为单位,但也可以使用其它的时间单位后缀。

  • us: 微秒(microseconds),即1/1000000秒;
  • ms: 毫秒(milliseconds),即1/1000秒;
  • s: 秒(seconds);
  • m: 分钟(minutes);
  • h:小时(hours);
  • d: 天(days);

3.简单案例

下面的例子配置了一个监听在所有接口的80端口上HTTP proxy服务,它转发所有的请求至后端监听在127.0.0.1:8000上的”server”。

global 
     daemon  
     maxconn 25600
 defaults 
     mode http  
     timeout connect 5000ms  
     timeout client 50000ms  
     timeout server 50000ms
 frontend http-in 
     bind *:80  
     default_backend servers
 backend servers 
     server server1 127.0.0.1:8080 maxconn 32

4.全局配置

注,“global”配置中的参数为进程级别的参数,且通常与其运行的OS相关。

(1).进程管理及安全相关的参数

  • chroot <jail dir>:修改haproxy的工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限;
  • daemon:让haproxy以守护进程的方式工作于后台,其等同于“-D”选项的功能,当然,也可以在命令行中以“-db”选项将其禁用;
  • gid <number>:以指定的GID运行haproxy,建议使用专用于运行haproxy的GID,以免因权限问题带来风险;
  • group <group name>:同gid,不过指定的组名;
  • log  <address> <facility> [max level [min level]]:定义全局的syslog服务器,最多可以定义两个;
  • log-send-hostname [<string>]:在syslog信息的首部添加当前主机名,可以为“string”指定的名称,也可以缺省使用当前主机名;
  • nbproc <number>:指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
  • pidfile:将所有进程的pid写入文件启动进程的用户必须有权限访问此文件
  • uid:以指定的UID身份运行haproxy进程;
  • ulimit-n:设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计算,因此不推荐修改此选项;
  • user:同uid,但使用的是用户名;
  • stats:
  • node:定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
  • description:当前实例的描述信息;

(2).性能调整相关的参数

  • maxconn <number>:设定每个haproxy进程所接受的最大并发连接数,其等同于命令行选项“n”;“ulimit n”自动计算的结果正是参照此参数设定的;
  • maxpipes <number>:haproxy使用pipe完成基于内核的tcp报文重组,此选项则用于设定每进程所允许使用的最大pipe个数;每个pipe会打开两个文件描述符,因此,“ulimit n”自动计算时会根据需要调大此值;默认为maxconn/4,其通常会显得过大;
  • noepoll:在Linux系统上禁用epoll机制;
  • nokqueue:在BSE系统上禁用kqueue机制;
  • nopoll:禁用poll机制;
  • nosepoll:在Linux禁用启发式epoll机制;
  • nosplice:禁止在Linux套接字上使用内核tcp重组,这会导致更多的recv/send系统调用;不过,在Linux 2.6.2528系列的内核上,tcp重组功能有bug存在;
  • spreadchecks <0..50, in percent>:在haproxy后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能会带来意外问题;此选项用于将其检查的时间间隔长度上增加或减小一定的随机时长;
  • tune.bufsize <number>:设定buffer的大小,同样的内存条件小,较小的值可以让haproxy有能力接受更多的并发连接,较大的值可以让某些应用程序使用较大的cookie信息;默认为16384,其可以在编译时修改,不过强烈建议使用默认值;
  • tune.chksize <number>:设定检查缓冲区的大小,单位为字节;更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更多的系统资源;不建议修改;
  • tune.maxaccept <number>:设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐率,默认在单进程模式下为100,多进程模式下为8,设定为1可以禁止此限制;一般不建议修改;
  • tune.maxpollevents  <number>:设定一次系统调用可以处理的事件最大数,默认值取决于OS;其值小于200时可节约带宽,但会略微增大网络延迟,而大于200时会降低延迟,但会稍稍增加网络带宽的占用量;
  • tune.maxrewrite <number>:设定为首部重写或追加而预留的缓冲空间,建议使用1024左右的大小;在需要使用更大的空间时,haproxy会自动增加其值;
    tune.rcvbuf.client <number>:
  • tune.rcvbuf.server <number>:设定内核套接字中服务端或客户端接收缓冲的大小,单位为字节;强烈推荐使用默认值;
  • tune.sndbuf.client:
  • tune.sndbuf.server:

(3).Debug相关的参数

  • debug
  • quiet

5.代理

代理相关的配置可以如下配置段中,

  • defaults <name>
  • frontend <name>
  • backend <name>
  • listen <name>

“defaults”段用于为所有其它配置段提供默认参数,这配置默认配置参数可由下一个“defaults”所重新设定。

“frontend”段用于定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接。

“backend”段用于定义一系列“后端”服务器,代理将会将对应客户端的请求转发至这些服务器。

“listen”段通过关联“前端”和“后端”定义了一个完整的代理,通常只对TCP流量有用。

注,所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分字母大小写。更详细的配置信息,请查阅官方文档

好了,下面我们来安装配置一下haproxy,更详细的配置文件内容,将会在后面进行补充。

八、安装与配置haproxy

1.实验拓扑

h1

2.环境准备

操作系统

  • CentOS 6.4 x86_64

软件版本

[root@node1 ~]# service httpd start
正在启动 httpd:                                           [确定]
[root@node2 ~]# service httpd start
正在启动 httpd:                                           [确定]
  • haproxy-1.4.22

安装httpd

[root@node1 ~]# yum install -y httpd
[root@node2 ~]# yum install -y httpd

提供测试文件

[root@node1 ~]# cat /var/www/html/index.html 
<h1>node1.test.com</h1>
[root@node2 ~]# cat /var/www/html/index.html 
<h1>node2.test.com</h1>

启动httpd

[root@node1 ~]# service httpd start
正在启动 httpd:                                           [确定]
[root@node2 ~]# service httpd start
正在启动 httpd:                                           [确定]

测试一下

node1

node2

3.安装yum源

[root@node1 ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@node2 ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@haproxy ~]# [root@node2 ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

4.同步时间

[root@node1 ~]# ntpdate 202.120.2.101
[root@node2 ~]# ntpdate 202.120.2.101
[root@haproxy ~]# ntpdate 202.120.2.101

5.关闭防火墙与SELinux

[root@node1 ~]# service iptables stop 
[root@node1 ~]# chkconfig iptables off  
[root@node1 ~]# getenforce  
Disabled
[root@node2 ~]# service iptables stop 
[root@node2 ~]# chkconfig iptables off  
[root@node2 ~]# getenforce  
Disabled
[root@haproxy ~]# service iptables stop 
[root@haproxy ~]# chkconfig iptables off  
[root@haproxy ~]# getenforce  
Disabled

6.安装haproxy

[root@haproxy ~]# yum install -y haproxy

7.查看一下安装文件

[root@haproxy ~]# rpm -ql haproxy 
/etc/haproxy #配置文件目录  
/etc/haproxy/haproxy.cfg #配置文件  
/etc/logrotate.d/haproxy  
/etc/rc.d/init.d/haproxy #启动脚本  
/usr/bin/halog  
/usr/sbin/haproxy #haproxy 命令  
/usr/share/doc/haproxy-1.4.22  
/usr/share/doc/haproxy-1.4.22/CHANGELOG  
/usr/share/doc/haproxy-1.4.22/LICENSE  
/usr/share/doc/haproxy-1.4.22/README  
/usr/share/doc/haproxy-1.4.22/acl-content-sw.cfg  
/usr/share/doc/haproxy-1.4.22/acl.fig  
/usr/share/doc/haproxy-1.4.22/architecture.txt  
/usr/share/doc/haproxy-1.4.22/configuration.txt  
/usr/share/doc/haproxy-1.4.22/content-sw-sample.cfg  
/usr/share/doc/haproxy-1.4.22/cttproxy-src.cfg  
/usr/share/doc/haproxy-1.4.22/design-thoughts  
/usr/share/doc/haproxy-1.4.22/design-thoughts/backends-v0.txt  
/usr/share/doc/haproxy-1.4.22/design-thoughts/backends.txt  
/usr/share/doc/haproxy-1.4.22/design-thoughts/be-fe-changes.txt  
/usr/share/doc/haproxy-1.4.22/design-thoughts/buffers.fig  
/usr/share/doc/haproxy-1.4.22/design-thoughts/config-language.txt  
/usr/share/doc/haproxy-1.4.22/design-thoughts/cttproxy-changes.txt  
/usr/share/doc/haproxy-1.4.22/design-thoughts/how-it-works.txt  
/usr/share/doc/haproxy-1.4.22/design-thoughts/http_load_time.url  
/usr/share/doc/haproxy-1.4.22/design-thoughts/sess_par_sec.txt  
/usr/share/doc/haproxy-1.4.22/gpl.txt  
/usr/share/doc/haproxy-1.4.22/haproxy-en.txt  
/usr/share/doc/haproxy-1.4.22/haproxy-fr.txt  
/usr/share/doc/haproxy-1.4.22/haproxy.1  
/usr/share/doc/haproxy-1.4.22/haproxy.cfg  
/usr/share/doc/haproxy-1.4.22/internals  
/usr/share/doc/haproxy-1.4.22/internals/connect-status.txt  
/usr/share/doc/haproxy-1.4.22/internals/connection-header.txt  
/usr/share/doc/haproxy-1.4.22/internals/connection-scale.txt  
/usr/share/doc/haproxy-1.4.22/internals/header-parser-speed.txt  
/usr/share/doc/haproxy-1.4.22/internals/header-tree.txt  
/usr/share/doc/haproxy-1.4.22/internals/http-cookies.txt  
/usr/share/doc/haproxy-1.4.22/internals/http-docs.txt  
/usr/share/doc/haproxy-1.4.22/internals/http-parsing.txt  
/usr/share/doc/haproxy-1.4.22/internals/naming.txt  
/usr/share/doc/haproxy-1.4.22/internals/repartition-be-fe-fi.txt  
/usr/share/doc/haproxy-1.4.22/internals/stats-v2.txt  
/usr/share/doc/haproxy-1.4.22/internals/stream-sock-states.fig  
/usr/share/doc/haproxy-1.4.22/internals/todo.cttproxy  
/usr/share/doc/haproxy-1.4.22/lgpl.txt  
/usr/share/doc/haproxy-1.4.22/queuing.fig  
/usr/share/doc/haproxy-1.4.22/tarpit.cfg  
/usr/share/doc/haproxy-1.4.22/url-switching.cfg  
/usr/share/haproxy  
/usr/share/haproxy/400.http  
/usr/share/haproxy/403.http  
/usr/share/haproxy/408.http  
/usr/share/haproxy/500.http  
/usr/share/haproxy/502.http  
/usr/share/haproxy/503.http  
/usr/share/haproxy/504.http  
/usr/share/haproxy/README  
/usr/share/man/man1/haproxy.1.gz #man 文档  
/var/lib/haproxy

8.haproxy 命令详解

[root@haproxy ~]# haproxy -h 
HA-Proxy version 1.4.22 2012/08/09  
Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
Usage : haproxy [-f <cfgfile>]* [ -vdVD ] [ -n <maxconn> ] [ -N <maxpconn> ] 
        [ -p <pidfile> ] [ -m <max megs> ]  
        -v displays version ; -vv shows known build options.  
        -d enters debug mode ; -db only disables background mode.  
        -V enters verbose mode (disables quiet mode)  
        -D goes daemon  
        -q quiet mode : don't display messages  
        -c check mode : only check config files and exit  
        -n sets the maximum total # of connections (2000)  
        -m limits the usable amount of memory (in MB)  
        -N sets the default, per-proxy maximum # of connections (2000)  
        -p writes pids of all children to this file  
        -de disables epoll() usage even when available  
        -ds disables speculative epoll() usage even when available  
        -dp disables poll() usage even when available  
        -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.
haproxy [-f < 配置文件>] [ -vdVD ] [-n 最大并发连接总数] [-N 每个侦听的最大并发数] 
[ -p <当前的PID文件> ] [-m <内存限制M>]
-v 显示当前版本信息;-vv 显示已知的创建选项 
-d 前台,debug模式;-db 禁用后台模式,程序跑在前台  
-V 详细模式  
-D daemon模式启动  
-q 安静模式,不输出信息  
-c 对配置文件进行语法检查  
-n 最大并发连接总数  
-m 限制的可用内存大小  
-N 设置默认的连接数  
-p 设置当前的PID文件  
-de 不使用epoll  
-ds 不使用speculative epoll  
-dp 不使用poll  
-sf 程序启动后向pidlist里的进程发送FINISH信号,这个参数放在命令行的最后  
-st 程序启动后向pidlist里的进程发送TERMINATE信号,这个参数放在命令行的最后

9.查看一下默认配置文件

[root@haproxy haproxy]# cat haproxy.cfg 
#---------------------------------------------------------------------  
# Example configuration for a possible web application.  See the  
# full configuration options online.  
#  
#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt  #官方配置文档,很详细,英文没问题的博友,可以看看 
#  
#---------------------------------------------------------------------
#--------------------------------------------------------------------- 
# Global settings #全局配置文件 
#---------------------------------------------------------------------  
global  
    # to have these messages end up in /var/log/haproxy.log you will  
    # need to:  #配置日志 
    #  
    # 1) configure syslog to accept network log events.  This is done  
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in  
    #    /etc/sysconfig/syslog #修改syslog配置文件 
    #  
    # 2) configure local2 events to go to the /var/log/haproxy.log  
    #   file. A line like the following can be added to  
    #   /etc/sysconfig/syslog  #定义日志设备 
    #  
    #    local2.*                       /var/log/haproxy.log  
    #  
    log         127.0.0.1 local2 #
#全局的日志配置 其中日志级别是[err warning info debug]
#local0 是日志设备,必须为如下24种标准syslog设备的一种:
#kern user mail daemon auth syslog lpr news
#uucp cron auth2 ftp ntp audit alert cron2
#local0 local1 local2 local3 local4 local5 local6 local7
    chroot      /var/lib/haproxy 
    pidfile     /var/run/haproxy.pid #将所有进程的pid写入文件启动进程的用户必须有权限访问此文件。 
    maxconn     4000 #最大连接数,默认4000 
    user        haproxy #用户 
    group       haproxy #组 
    daemon ##创建1个进程进入deamon模式运行。此参数要求将运行模式设置为"daemon"
    # turn on stats unix socket  #unix socket 文件
    stats socket /var/lib/haproxy/stats
#--------------------------------------------------------------------- 
# common defaults that all the 'listen' and 'backend' sections will  
# use if not designated in their block  #默认的全局设置,这些参数可以被利用配置到frontend,backend,listen组件 
#---------------------------------------------------------------------  
defaults
    mode                    http  #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK 
    log                     global #采用全局定义的日志 
    option                  httplog #日志类别http日志格式
    option                  dontlognull #不记录健康检查的日志信息
    option http-server-close #每次请求完毕后主动关闭http通道
    option forwardfor       except 127.0.0.0/8 #不记录本机转发的日志 
    option                  redispatch #serverId对应的服务器挂掉后,强制定向到其他健康的服务器 
    retries                 3 #3次连接失败就认为服务不可用,也可以通过后面设置 
    timeout http-request    10s  #请求超时 
    timeout queue           1m #队列超时 
    timeout connect         10s #连接超时 
    timeout client          1m #客户端连接超时 
    timeout server          1m #服务器连接超时 
    timeout http-keep-alive 10s #长连接超时 
    timeout check           10s  #检查超时 
    maxconn                 3000 #最大连接数
#--------------------------------------------------------------------- 
# main frontend which proxys to the backends #frontend 与backends  代理配置 
#---------------------------------------------------------------------  
frontend  main *:5000
#acl策略配置
    acl url_static       path_beg       -i /static /images /javascript /stylesheets  
    acl url_static       path_end       -i .jpg .gif .png .css .js
    use_backend static          if url_static  #满足策略要求,则响应策略定义的backend页面
    default_backend             app #不满足则响应backend的默认页面
#--------------------------------------------------------------------- 
# static backend for serving up images, stylesheets and such #定义使用静态后端图像,样式表等 
#---------------------------------------------------------------------  
backend static  
    balance     roundrobin #负载均衡模式轮询 
    server      static 127.0.0.1:4331 check #服务器定义
#--------------------------------------------------------------------- 
# round robin balancing between the various backends  
#---------------------------------------------------------------------  
backend app  
    balance     roundrobin #负载均衡模式轮询 
    server  app1 127.0.0.1:5001 check #服务器定义,check进行健康检查 
    server  app2 127.0.0.1:5002 check  
    server  app3 127.0.0.1:5003 check  
    server  app4 127.0.0.1:5004 check

好了,默认的配置文件我们就说到这里,相信大家对配置文件已有了大致的了解,下面我们配置一个案例,让大家更深入的了解haproxy。

九、haproxy 案例演示

1.负载均衡Web服务器的案例

#---------------------------------------------------------------------
# Global settings 
#--------------------------------------------------------------------- 
global 
    # to have these messages end up in /var/log/haproxy.log you will 
    # need to: 
    # 
    # 1) configure syslog to accept network log events.  This is done 
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in 
    #    /etc/sysconfig/syslog 
    # 
    # 2) configure local2 events to go to the /var/log/haproxy.log 
    #   file. A line like the following can be added to 
    #   /etc/sysconfig/syslog 
    # 
    #    local2.*                       /var/log/haproxy.log 
    # 
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid 
    maxconn     4000 
    user        haproxy 
    group       haproxy 
    daemon
defaults
    mode                    http 
    log                     global 
    option                  httplog 
    option                  dontlognull 
    option http-server-close 
    option forwardfor       except 127.0.0.0/8 
    option                  redispatch 
    retries                 3 
    timeout http-request    10s 
    timeout queue           1m 
    timeout connect         10s 
    timeout client          1m 
    timeout server          1m 
    timeout http-keep-alive 10s 
    timeout check           10s 
    maxconn                 30000
listen stats
    mode http 
    bind 0.0.0.0:1080 
    stats enable 
    stats hide-version 
    stats uri     /haproxyadmin?stats 
    stats realm   Haproxy\ Statistics 
    stats auth    admin:admin 
    stats admin if TRUE
frontend http-in 
    bind *:80 
    mode http 
    log global 
    option httpclose 
    option logasap 
    option dontlognull 
    capture request  header Host len 20 
    capture request  header Referer len 60 
    default_backend servers
frontend healthcheck
    bind :1099 
    mode http 
    option httpclose 
    option forwardfor 
    default_backend servers
backend servers
    balance roundrobin 
    server websrv1 192.168.18.201:80 check maxconn 2000 
    server websrv2 192.168.18.202:80 check maxconn 2000

注,首先我们来配置一下日志,不然haproxy无法记录日志。

2.配置haproxy日志(注,配置方法配置文件中已说明,我们这里来演示一下。)

(1).修改系统日志的配置文件
[root@haproxy ~]# vim /etc/sysconfig/rsyslog
# Options for rsyslogd
# Syslogd options are deprecated since rsyslog v3. 
# If you want to use them, switch to compatibility mode 2 by "-c 2" 
# See rsyslogd(8) for more details 
SYSLOGD_OPTIONS="-c 2 -r"

(2).增加日志设备

[root@haproxy ~]# vim /etc/rsyslog.conf
#增加一行
local2.*                                                /var/log/haproxy.log

(3).重新启动一下日志服务

[root@haproxy ~]# service rsyslog restart
关闭系统日志记录器:                                       [确定] 
启动系统日志记录器:                                       [确定]

3.修改haproxy配置文件

[root@haproxy ~]# cat /etc/haproxy/haproxy.cfg
#--------------------------------------------------------------------- 
# Global settings 
#--------------------------------------------------------------------- 
global 
    # to have these messages end up in /var/log/haproxy.log you will 
    # need to: 
    # 
    # 1) configure syslog to accept network log events.  This is done 
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in 
    #    /etc/sysconfig/syslog 
    # 
    # 2) configure local2 events to go to the /var/log/haproxy.log 
    #   file. A line like the following can be added to 
    #   /etc/sysconfig/syslog 
    # 
    #    local2.*                       /var/log/haproxy.log 
    # 
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid 
    maxconn     4000 
    user        haproxy 
    group       haproxy 
    daemon
defaults
    mode                    http 
    log                     global 
    option                  httplog 
    option                  dontlognull 
    option http-server-close 
    option forwardfor       except 127.0.0.0/8 
    option                  redispatch 
    retries                 3 
    timeout http-request    10s 
    timeout queue           1m 
    timeout connect         10s 
    timeout client          1m 
    timeout server          1m 
    timeout http-keep-alive 10s 
    timeout check           10s 
    maxconn                 30000
listen stats
    mode http 
    bind 0.0.0.0:1080 
    stats enable 
    stats hide-version 
    stats uri     /haproxyadmin?stats 
    stats realm   Haproxy\ Statistics 
    stats auth    admin:admin 
    stats admin if TRUE
frontend http-in 
    bind *:80 
    mode http 
    log global 
    option httpclose 
    option logasap 
    option dontlognull 
    capture request  header Host len 20 
    capture request  header Referer len 60 
    default_backend servers
frontend healthcheck
    bind :1099 
    mode http 
    option httpclose 
    option forwardfor 
    default_backend servers
backend servers
    balance roundrobin 
    server websrv1 192.168.18.201:80 check maxconn 2000 
    server websrv2 192.168.18.202:80 check maxconn 2000

4.查检一下配置文件

[root@haproxy ~]# haproxy -c -f /etc/haproxy/haproxy.cfg
Configuration file is valid

5.启动haproxy

[root@haproxy ~]# service haproxy start
正在启动 haproxy:

6.查看一下端口

[root@haproxy ~]# netstat -ntulp | grep :80
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      3695/haproxy

7.测试一下

test1

test2

注,大家可以看到,你不断的刷新,node1与node2在不停的切换,说明我们的haproxy负载均衡配置成功。

8.配置文件详解

注,现在大家再来看这个配置文件应该就很容易理解了。好了,下面我们来具体说一下。

[root@haproxy ~]# cat /etc/haproxy/haproxy.cfg
#--------------------------------------------------------------------- 
# Global settings 全局配置 
#--------------------------------------------------------------------- 
global  
    # to have these messages end up in /var/log/haproxy.log you will 
    # need to: 
    # 
    # 1) configure syslog to accept network log events.  This is done 
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in 
    #    /etc/sysconfig/syslog 
    # 
    # 2) configure local2 events to go to the /var/log/haproxy.log 
    #   file. A line like the following can be added to 
    #   /etc/sysconfig/syslog 
    # 
    #    local2.*                       /var/log/haproxy.log 
    #
#上面的注释是告诉我们怎么配置日志的
    log         127.0.0.1  local2 #定义日志
    chroot      /var/lib/haproxy #安全模式
    pidfile     /var/run/haproxy.pid #pid文件 
    maxconn     4000 #最大连接数 
    user        haproxy #用户 
    group       haproxy #组合 
    daemon
 #---------------------------------------------------------------------
# Proxy settings 代理配置,下面全是代理配置
#---------------------------------------------------------------------
defaults #配置默认参数的,这些参数可以被利用配置到frontend,backend,listen组件
    mode                    http #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK(注,health已经废弃) 
    log                     global #采用全局定义的日志 
    option                  httplog #日志类别http日志格式
    option                  dontlognull #不记录健康检查的日志信息
    option http-server-close #每次请求完毕后主动关闭http通道
    option forwardfor       except 127.0.0.0/8 #不记录本机转发的日志 
    option                  redispatch #serverId对应的服务器挂掉后,强制定向到其他健康的服务器 
    retries                 3 #3次连接失败就认为服务不可用,也可以通过后面设置 
    timeout http-request    10s  #请求超时 
    timeout queue           1m #队列超时 
    timeout connect         10s #连接超时 
    timeout client          1m #客户端连接超时 
    timeout server          1m #服务器连接超时 
    timeout http-keep-alive 10s #长连接超时 
    timeout check           10s  #检查超时 
    maxconn                 30000 #最大连接数
listen stats #listen是Frontend和Backend的组合体。这里定义的是haproxy监控!
    mode http #模式http 
    bind 0.0.0.0:1080 #绑定的监控ip与端口 
    stats enable #启用监控
    stats hide-version #隐藏haproxy版本  
    stats uri     /haproxyadmin?stats #定义的uri 
    stats realm   Haproxy\ Statistics #定义显示文字 
    stats auth    admin:admin #认证 
    stats admin if TRUE
frontend http-in #接收请求的前端虚拟节点,Frontend可以根据规则直接指定具体使用后端的 backend(可动态选择)。这里定义的是http服务! 
    bind *:80   #绑定的监控ip与端口 
    mode http #模式http 
    log global #定义日志 
    option httpclose #每次请求完毕后主动关闭http通道 
    option logasap # 
    option dontlognull ##不记录健康检查的日志信息 
    capture request  header Host len 20  
    capture request  header Referer len 60 
    default_backend servers #定义的默认backend
frontend healthcheck
    bind :1099 
    mode http 
    option httpclose 
    option forwardfor 
    default_backend servers #定义的默认backend
backend servers #后端服务集群的配置,是真实的服务器,一个Backend对应一个或者多个实体服务器。
    balance roundrobin #负载均衡方式为轮询 
    server websrv1 192.168.18.201:80 check maxconn 2000 #定义server,check 健康检查,maxconn 定义最大连接数 
    server websrv2 192.168.18.202:80 check maxconn 2000
好了,到这里我们案例就讲解完成了,下面我们再来补充一下,配置文件中的常用关键字参考。

十、haproxy 配置文件中的关键字参考

1.balance

格式:

balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post [<max_wait>]]

定义负载均衡算法,可用于“defaults”、“listen”和“backend”。<algorithm>用于在负载均衡场景中挑选一个server,其仅应用于持久信息不可用的条件下或需要将一个连接重新派发至另一个服务器时。支持的算法有:

  • roundrobin:基于权重进行轮叫,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,这表示其权重可以在运行时进行调整,不过,在设计上,每个后端服务器仅能最多接受4128个连接;
  • static-rr:基于权重进行轮叫,与roundrobin类似,但是为静态方法,在运行时调整其服务器权重不会生效;不过,其在后端服务器连接数上没有限制;
  • leastconn:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重;
  • source:将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议;其默认为静态,不过也可以使用hash-type修改此特性;
  • uri:对URI的左半部分(“问题”标记之前的部分)或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代理以提高缓存的命中率;需要注意的是,此算法仅应用于HTTP后端服务器场景;其默认为静态算法,不过也可以使用hash-type修改此特性;
  • url_param:通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,那么此值将被执行hash运算并被服务器的总权重相除后派发至某匹配的服务器;此算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度;此算法默认为静态的,不过其也可以使用hash-type修改此特性;
  • hdr(<name>):对于每个HTTP请求,通过<name>指定的HTTP首部将会被检索;如果相应的首部没有出现或其没有有效值,则使用轮叫算法对相应请求进行调度;其有一个可选选项“use_domain_only”,可在指定检索类似Host类的首部时仅计算域名部分(比如通过www.test.com来说,仅计算test字符串的hash值)以降低hash算法的运算量;此算法默认为静态的,不过其也可以使用hash-type修改此特性;
    rdp-cookie
    rdp-cookie(name)

2.bind

格式:

bind [<address>]:<port_range> [, …]
bind [<address>]:<port_range> [, …] interface <interface>

此指令仅能用于frontend和listen区段,用于定义一个或几个监听的套接字。

  • <address>:可选选项,其可以为主机名、IPv4地址、IPv6地址或*;省略此选项、将其指定为*或0.0.0.0时,将监听当前系统的所有IPv4地址;
  • <port_range>:可以是一个特定的TCP端口,也可是一个端口范围(如5005-5010),代理服务器将通过指定的端口来接收客户端请求;需要注意的是,每组监听的套接字<address:port>在同一个实例上只能使用一次,而且小于1024的端口需要有特定权限的用户才能使用,这可能需要通过uid参数来定义;
  • <interface>:指定物理接口的名称,仅能在Linux系统上使用;其不能使用接口别名,而仅能使用物理接口名称,而且只有管理有权限指定绑定的物理接口;

3.mode

格式:

mode { tcp|http|health }

设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般说来都是HTTP模式),否则将无法启动实例。

  • tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;此为默认模式,通常用于SSL、SSH、SMTP等应用;
  • http:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;
  • health:实例工作于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前来讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能;

4. hash-type

格式:

hash-type <method>

定义用于将hash码映射至后端服务器的方法;其不能用于frontend区段;可用方法有map-based和consistent,在大多数场景下推荐使用默认的map-based方法。

  • map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
  • consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。

5.log

格式:

log global
log <address> <facility> [<level> [<minlevel>]]

为每个实例启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个log参数,不过,如果使用了“log global”且”global”段已经定了两个log参数时,多余了log参数将被忽略。

  • global:当前实例的日志系统参数同”global”段中的定义时,将使用此格式;每个实例仅能定义一次“log global”语句,且其没有任何额外参数;
  • <address>:定义日志发往的位置,其格式之一可以为<IPv4_address:PORT>,其中的port为UDP协议端口,默认为514;格式之二为Unix套接字文件路径,但需要留心chroot应用及用户的读写权限;
  • <facility>:可以为syslog系统的标准facility之一;
  • <level>:定义日志级别,即输出信息过滤器,默认为所有信息;指定级别时,所有等于或高于此级别的日志信息将会被发送;

6.maxconn

格式:

maxconn <conns>

设定一个前端的最大并发连接数,因此,其不能用于backend区段。对于大型站点来说,可以尽可能提高此值以便让haproxy管理连接队列,从而避免无法应答用户请求。当然,此最大值不能超出“global”段中的定义。此外,需要留心的是,haproxy会为每个连接维持两个缓冲,每个缓冲的大小为8KB,再加上其它的数据,每个连接将大约占用17KB的RAM空间。这意味着经过适当优化后,有着1GB的可用RAM空间时将能维护40000-50000并发连接。

如果为<conns>指定了一个过大值,极端场景下,其最终占据的空间可能会超出当前主机的可用内存,这可能会带来意想不到的结果;因此,将其设定了一个可接受值方为明智决定。其默认为2000。

7.default_backend

格式:

default_backend <backend>

在没有匹配的”use_backend”规则时为实例指定使用的默认后端,因此,其不可应用于backend区段。在”frontend”和”backend”之间进行内容交换时,通常使用”use-backend”定义其匹配规则;而没有被规则匹配到的请求将由此参数指定的后端接收。

<backend>:指定使用的后端的名称;

使用案例:

use_backend     dynamic  if  url_dyn
use_backend     static   if  url_css url_img extension_img 
default_backend dynamic

8.server

格式:

server <name> <address>[:port] [param*]

为后端声明一个server,因此,不能用于defaults和frontend区段。

  • <name>:为此服务器指定的内部名称,其将出现在日志及警告信息中;如果设定了”http-send-server-name”,它还将被添加至发往此服务器的请求首部中;
  • <address>:此服务器的的IPv4地址,也支持使用可解析的主机名,只不过在启动时需要解析主机名至相应的IPv4地址;
  • [:port]:指定将连接请求所发往的此服务器时的目标端口,其为可选项;未设定时,将使用客户端请求时的同一相端口;
  • [param*]:为此服务器设定的一系参数;其可用的参数非常多,具体请参考官方文档中的说明,下面仅说明几个常用的参数;

服务器或默认服务器参数:

  • backup:设定为备用服务器,仅在负载均衡场景中的其它server均不可用于启用此server;
  • check:启动对此server执行健康状态检查,其可以借助于额外的其它参数完成更精细的设定,如:
    inter <delay>:设定健康状态检查的时间间隔,单位为毫秒,默认为2000;也可以使用fastinter和downinter来根据服务器端状态优化此时间延迟;
    rise <count>:设定健康状态检查中,某离线的server从离线状态转换至正常状态需要成功检查的次数;
    fall <count>:确认server从正常状态转换为不可用状态需要检查的次数;
  • cookie <value>:为指定server设定cookie值,此处指定的值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,其目的在于实现持久连接的功能;
  • maxconn <maxconn>:指定此服务器接受的最大并发连接数;如果发往此服务器的连接数目高于此处指定的值,其将被放置于请求队列,以等待其它连接被释放;
  • maxqueue <maxqueue>:设定请求队列的最大长度;
  • observe <mode>:通过观察服务器的通信状况来判定其健康状态,默认为禁用,其支持的类型有“layer4”和“layer7”,“layer7”仅能用于http代理场景;
  • redir <prefix>:启用重定向功能,将发往此服务器的GET和HEAD请求均以302状态码响应;需要注意的是,在prefix后面不能使用/,且不能使用相对地址,以免造成循环;例如:server srv1 172.16.100.6:80 redirhttp://imageserver.test.com check
  • weight <weight>:权重,默认为1,最大值为256,0表示不参与负载均衡;

检查方法:
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>:不能用于frontend段,例如:

backend https_relay
    mode tcp
    option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www.test.com
    server apache1 192.168.1.1:443 check port 80

使用案例:

server first  172.16.100.7:1080 cookie first  check inter 1000 
server second 172.16.100.8:1080 cookie second check inter 1000

9.capture request header

格式:

capture request header <name> len <length>

捕获并记录指定的请求首部最近一次出现时的第一个值,仅能用于“frontend”和“listen”区段。捕获的首部值使用花括号{}括起来后添加进日志中。如果需要捕获多个首部值,它们将以指定的次序出现在日志文件中,并以竖线“|”作为分隔符。不存在的首部记录为空字符串,最常需要捕获的首部包括在虚拟主机环境中使用的“Host”、上传请求首部中的“Content-length”、快速区别真实用户和网络机器人的“User-agent”,以及代理环境中记录真实请求来源的“X-Forward-For”。

  • <name>:要捕获的首部的名称,此名称不区分字符大小写,但建议与它们出现在首部中的格式相同,比如大写首字母。需要注意的是,记录在日志中的是首部对应的值,而非首部名称。
  • <length>:指定记录首部值时所记录的精确长度,超出的部分将会被忽略。

可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录64个字符。为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义。

10.capture response header

格式:

capture response header <name> len <length>

捕获并记录响应首部,其格式和要点同请求首部。

11.stats enable

格式:

启用基于程序编译时默认设置的统计报告,不能用于“frontend”区段。只要没有另外的其它设定,它们就会使用如下的配置:

stats uri   : /haproxy?stats
stats realm : "HAProxy Statistics" 
stats auth  : no authentication 
stats scope : no restriction

尽管“stats enable”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。下面是一个配置案例。

backend public_www
  server websrv1 172.16.100.11:80 
  stats enable 
  stats hide-version 
  stats scope   . 
  stats uri     /haproxyadmin?stats 
  stats realm   Haproxy\ Statistics 
  stats auth    statsadmin:password 
  stats auth    statsmaster:password

12.stats hide-version

格式:

stats hide-version

启用统计报告并隐藏HAProxy版本报告,不能用于“frontend”区段。默认情况下,统计页面会显示一些有用信息,包括HAProxy的版本号,然而,向所有人公开HAProxy的精确版本号是非常有风险的,因为它能帮助恶意用户快速定位版本的缺陷和漏洞。尽管“stats hide-version”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。具体请参照“stats enable”一节的说明。

13.stats realm

格式:

stats realm <realm>

启用统计报告并高精认证领域,不能用于“frontend”区段。haproxy在读取realm时会将其视作一个单词,因此,中间的任何空白字符都必须使用反斜线进行转义。此参数仅在与“stats auth”配置使用时有意义。

  • <realm>:实现HTTP基本认证时显示在浏览器中的领域名称,用于提示用户输入一个用户名和密码。

尽管“stats realm”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。具体请参照“stats enable”一节的说明。

14.stats scope

格式:

stats scope { <name> | “.” }

启用统计报告并限定报告的区段,不能用于“frontend”区段。当指定此语句时,统计报告将仅显示其列举出区段的报告信息,所有其它区段的信息将被隐藏。如果需要显示多个区段的统计报告,此语句可以定义多次。需要注意的是,区段名称检测仅仅是以字符串比较的方式进行,它不会真检测指定的区段是否真正存在。

  • <name>:可以是一个“listen”、“frontend”或“backend”区段的名称,而“.”则表示stats scope语句所定义的当前区段。

尽管“stats scope”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。下面是一个配置案例。

backend private_monitoring
    stats enable 
    stats uri     /haproxyadmin?stats 
    stats refresh 10s

15.stats auth

格式:

stats auth <user>:<passwd>

启用带认证的统计报告功能并授权一个用户帐号,其不能用于“frontend”区段。

  • <user>:授权进行访问的用户名;
  • <passwd>:此用户的访问密码,明文格式;

此语句将基于默认设定启用统计报告功能,并仅允许其定义的用户访问,其也可以定义多次以授权多个用户帐号。可以结合“stats realm”参数在提示用户认证时给出一个领域说明信息。在使用非法用户访问统计功能时,其将会响应一个“401 Forbidden”页面。其认证方式为HTTP Basic认证,密码传输会以明文方式进行,因此,配置文件中也使用明文方式存储以说明其非保密信息故此不能相同于其它关键性帐号的密码。

尽管“stats auth”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。

16.stats admin

stats admin { if | unless } <cond>

在指定的条件满足时启用统计报告页面的管理级别功能,它允许通过web接口启用或禁用服务器,不过,基于安全的角度考虑,统计报告页面应该尽可能为只读的。此外,如果启用了HAProxy的多进程模式,启用此管理级别将有可能导致异常行为。

目前来说,POST请求方法被限制于仅能使用缓冲区减去保留部分之外的空间,因此,服务器列表不能过长,否则,此请求将无法正常工作。因此,建议一次仅调整少数几个服务器。下面是两个案例,第一个限制了仅能在本机打开报告页面时启用管理级别功能,第二个定义了仅允许通过认证的用户使用管理级别功能。

backend stats_localhost
    stats enable 
    stats admin if LOCALHOST
backend stats_auth
    stats enable 
    stats auth  haproxyadmin:password 
    stats admin if TRUE

17.option httplog

格式:

option httplog [ clf ]

启用记录HTTP请求、会话状态和计时器的功能。

clf:使用CLF格式来代替HAProxy默认的HTTP格式,通常在使用仅支持CLF格式的特定日志分析器时才需要使用此格式。

默认情况下,日志输入格式非常简陋,因为其仅包括源地址、目标地址和实例名称,而“option httplog”参数将会使得日志格式变得丰富许多,其通常包括但不限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、“frontend”、“backend”及服务器名称,当然也包括源地址和端口号等。

18.option logasap
格式:

option logasap
no option logasap

启用或禁用提前将HTTP请求记入日志,不能用于“backend”区段。

默认情况下,HTTP请求是在请求结束时进行记录以便能将其整体传输时长和字节数记入日志,由此,传较大的对象时,其记入日志的时长可能会略有延迟。“option logasap”参数能够在服务器发送complete首部时即时记录日志,只不过,此时将不记录整体传输时长和字节数。此情形下,捕获“Content-Length”响应首部来记录传输的字节数是一个较好选择。下面是一个例子。

listen http_proxy 0.0.0.0:80
    mode http 
    option httplog 
    option logasap 
    log 172.16.100.9 local2

19.option forwardfor

格式:

option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

允许在发往服务器的请求首部中插入“X-Forwarded-For”首部。

  • <network>:可选参数,当指定时,源地址为匹配至此网络中的请求都禁用此功能。
  • <name>:可选参数,可使用一个自定义的首部,如“X-Client”来替代“X-Forwarded-For”。有些独特的web服务器的确需要用于一个独特的首部。
  • if-none:仅在此首部不存在时才将其添加至请求报文问道中。

HAProxy工作于反向代理模式,其发往服务器的请求中的客户端IP均为HAProxy主机的地址而非真正客户端的地址,这会使得服务器端的日志信息记录不了真正的请求来源,“X-Forwarded-For”首部则可用于解决此问题。HAProxy可以向每个发往服务器的请求上添加此首部,并以客户端IP为其value。

需要注意的是,HAProxy工作于隧道模式,其仅检查每一个连接的第一个请求,因此,仅第一个请求报文被附加此首部。如果想为每一个请求都附加此首部,请确保同时使用了“option httpclose”、“option forceclose”和“option http-server-close”几个option。

下面是一个例子。

frontend www
    mode http 
    option forwardfor except 127.0.0.1

20.errorfile

格式:

errorfile <code> <file>

在用户请求不存在的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。

  • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
  • <file>:指定用于响应的页面文件;

例如:

errorfile 400 /etc/haproxy/errorpages/400badreq.http 
errorfile 403 /etc/haproxy/errorpages/403forbid.http 
errorfile 503 /etc/haproxy/errorpages/503sorry.http

21.errorloc 和 errorloc302

格式:

errorloc <code> <url>
errorloc302 <code> <url>
请求错误时,返回一个HTTP重定向至某URL的信息;可用于所有配置段中。

  • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
  • <url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;

需要留意的是,这两个关键字都会返回302状态吗,这将使得客户端使用同样的HTTP方法获取指定的URL,对于非GET法的场景(如POST)来说会产生问题,因为返回客户的URL是不允许使用GET以外的其它方法的。如果的确有这种问题,可以使用errorloc303来返回303状态码给客户端。

22.errorloc303

errorloc303 <code> <url>

请求错误时,返回一个HTTP重定向至某URL的信息给客户端;可用于所有配置段中。

  • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有400、403、408、500、502、503和504;
  • <url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;

例如:

backend webserver
  server 172.16.100.6 172.16.100.6:80 check maxconn 3000 cookie srv01 
  server 172.16.100.7 172.16.100.7:80 check maxconn 3000 cookie srv02 
  errorloc 403 /etc/haproxy/errorpages/sorry.htm 
  errorloc 503 /etc/haproxy/errorpages/sorry.htm

好了,到这里配置文件中常用的关键字就说到这里了,下面我们来说一下haproxy的监控。

十一、haproxy 监控功能详解

注,在上面的案例中我们已经配置了监控功能 ,下面我们就来访问一下吧。

1.浏览器访问一下 http://192.168.18.208:1080/haproxyadmin?stats

stats

2.模拟一下故障

[root@node1 ~]# service httpd stop
停止 httpd:                                               [确定]

3.再次查看一下监控

stats2

ststs3

好了,监控我们就简单的说到这里,更详细的内容,大家可以自己去查看。下面我们最后来说个案例。

十二、haproxy 负载均衡MySQL服务的配置示例

#---------------------------------------------------------------------
# Global settings 
#--------------------------------------------------------------------- 
global 
    # to have these messages end up in /var/log/haproxy.log you will 
    # need to: 
    # 
    # 1) configure syslog to accept network log events.  This is done 
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in 
    #    /etc/sysconfig/syslog 
    # 
    # 2) configure local2 events to go to the /var/log/haproxy.log 
    #   file. A line like the following can be added to 
    #   /etc/sysconfig/syslog 
    # 
    #    local2.*                       /var/log/haproxy.log 
    # 
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid 
    maxconn     4000 
    user        haproxy 
    group       haproxy 
    daemon
defaults
    mode                    tcp 
    log                     global 
    option                  httplog 
    option                  dontlognull 
    retries                 3 
    timeout http-request    10s 
    timeout queue           1m 
    timeout connect         10s 
    timeout client          1m 
    timeout server          1m 
    timeout http-keep-alive 10s 
    timeout check           10s 
    maxconn                 600
listen stats
    mode http 
    bind 0.0.0.0:1080 
    stats enable 
    stats hide-version 
    stats uri     /haproxyadmin?stats 
    stats realm   Haproxy\ Statistics 
    stats auth    admin:admin 
    stats admin if TRUE
frontend mysql 
    bind *:3306 
    mode tcp 
    log global 
    default_backend mysqlservers
backend mysqlservers
    balance leastconn 
    server dbsrv1 192.168.10.11:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300 
    server dbsrv2 192.168.10.12:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300

好了,这篇博客这到这里了,在下一篇博客中我们将讲解varnish相关内容,最后想说,希望大家有所收获^_^……

发表在 Linux | 留下评论

vuejs todo list & webpack

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
    <title></title>
</head>

<body>
    <div id="app">
        <input type="text" v-model="newTodo" v-on:keyup.enter="addTodo" />
        <ul>
            <li v-for="todo in todos">
                <span>{{ todo.text }}</span>
                <button v-on:click="removeTodo($index)">X</button>
            </li>
        </ul>
    </div>
    <script src="./dist/vendor.bundle.js"></script>
    <script src="./dist/bundle.js"></script>
</body>

</html>
require(['vue'], function(Vue) {
    new Vue({
        el: '#app',
        data: {
            newTodo: '',
            todos: [
                { text: 'Add some todos' }
            ]
        },
        methods: {
            addTodo: function() {
                var text = this.newTodo.trim();
                if (text) {
                    this.todos.push({ text: text });
                }
                this.newTodo = '';
            },

            removeTodo: function(index) {
                this.todos.splice(index, 1);
            }
        }
    });
});

 

发表在 前端技术 | 标签为 , | 留下评论

JavaScript 冒泡排序

<script>
var arr = [5, 9, 7, 6, 1, 8, 13, 4];
var m = len = arr.length;

for (var i = 1; i < len; i++) {
    m -= 1;

    for (var j = 0; j < m; j++) {
        if (arr[j] > arr[j + 1]) {
            var tmp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = tmp;
        }
    }

    m++;
}

console.log(arr);
</script>

 

发表在 Linux | 留下评论

laravel 处理多文件上传

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
 */

use Illuminate\Http\Request;

Route::get('/', function () {
	return view('welcome');
});

Route::post('upload', function (Request $request) {
	$files = $request->file('file');
	if (!empty($files)) {
		foreach ($files as $file) {
			Storage::put($file->getClientOriginalName(), file_get_contents($file));
		}
	}

	return response()->json([
		'success' => true,
	]);
});
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <form action="upload" method="post" id="upload" enctype="multipart/form-data">
    	{{ csrf_field() }}
    	<input type="file" name="file[]" multiple="multiple" /> <br />
    	<input type="submit" value="upload" />
    </form>

    <div id="message"></div>

    <script>
    	var form = document.getElementById('upload');
    	var request = new XMLHttpRequest();

    	form.addEventListener('submit', function(e) {
    		e.preventDefault();

    		var formData = new FormData(form);

    		request.open('post', '/upload');
    		request.addEventListener('load', transferComplete);
    		request.send(formData);
    	});

    	function transferComplete(data) {
    		var response = JSON.parse(data.currentTarget.response);
    		if(response.success) {
    			document.getElementById('message').innerHTML = 'Successfully Uploaded Files';
    		}
    	}
    </script>
</body>
</html>

 

发表在 Linux | 留下评论

laravel 泛解析

Route::group(['domain' => '{name}.laravel.dev'], function () {
	Route::get('/foo/{id}', function ($name, $id) {
		echo $name . $id;
	});
});

Route::get('/', function () {
	echo 'home page';
});

 

发表在 Linux | 留下评论

浏览器 HTTP 协议缓存机制详解

原文:http://my.oschina.net/leejun2005/blog/369148#OSC_h1_1

最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control、为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag,有时又没有带?等等。。。

后来查了一些资料以及同事亲自验证,总算对这些问题有了个清晰的理解,现在整理出来以备忘。

1、缓存的分类

缓存分为服务端侧(server side,比如 Nginx、Apache)和客户端侧(client side,比如 web browser)。

服务端缓存又分为 代理服务器缓存 和 反向代理服务器缓存(也叫网关缓存,比如 Nginx反向代理、Squid等),其实广泛使用的 CDN 也是一种服务端缓存,目的都是让用户的请求走”捷径“,并且都是缓存图片、文件等静态资源。

客户端侧缓存一般指的是浏览器缓存,目的就是加速各种静态资源的访问,想想现在的大型网站,随便一个页面都是一两百个请求,每天 pv 都是亿级别,如果没有缓存,用户体验会急剧下降、同时服务器压力和网络带宽都面临严重的考验。

2、浏览器缓存机制详解

浏览器缓存控制机制有两种:HTML Meta标签 vs. HTTP头信息

2.1 HTML Meta标签控制缓存

浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires; Cache-control等)。但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的<head>节点中加入<meta>标签,代码如下:

1
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。而广泛应用的还是 HTTP头信息 来控制缓存,下面我主要介绍HTTP协议定义的缓存机制。

2.2 HTTP头信息控制缓存

2.2.1 浏览器请求流程

  • 浏览器第一次请求流程图:

  • 浏览器再次请求时:

2.2.2 几个重要概念解释

  • Expires策略:Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。Expires 的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大(比如时钟不同步,或者跨时区),那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。
  • Cache-control策略(重点关注):Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。
1
2
3
4
5
6
7
8
9
值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age
各个消息中的指令含义如下:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存,该选项并不是说可以设置”不缓存“,容易望文生义~
no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存,完全不存下來。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
  • Last-Modified/If-Modified-Since:Last-Modified/If-Modified-Since要配合Cache-Control使用。
1
2
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
  • Etag/If-None-Match:Etag/If-None-Match也要配合Cache-Control使用。
1
2
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
  • 既生Last-Modified何生Etag?你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
1
2
3
Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag一起使用时,服务器会优先验证ETag。

  • yahoo的Yslow法则中则提示谨慎设置Etag:需要注意的是分布式系统里多台机器间文件的last-modified必须保持一致,以免负载均衡到不同机器导致比对失败,Yahoo建议分布式系统尽量关闭掉Etag(每台机器生成的etag都会不一样,因为除了 last-modified、inode 也很难保持一致)。
  • Pragma行是为了兼容HTTP1.0,作用与Cache-Control: no-cache是一样的。
  • 最后总结下几种状态码的区别:

3、用户行为与缓存

浏览器缓存行为还有用户的行为有关,如果大家对 强制刷新(Ctrl + F5) 还有印象的话应该能立刻明白我的意思~

用户操作 Expires/Cache-Control Last-Modified/Etag
地址栏回车 有效 有效
页面链接跳转 有效 有效
新开窗口 有效 有效
前进、后退 有效 有效
F5/按钮刷新 无效(BR重置max-age=0) 有效
Ctrl+F5刷新 无效(重置CC=no-cache) 无效(请求头丢弃该选项)

具体请参考文末 Refer [6]

4、Refer:

[1] 浏览器缓存机制

http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html

[2] Web 开发人员需知的 Web 缓存知识

http://www.oschina.net/news/41397/web-cache-knowledge

[3] 浏览器缓存详解:expires,cache-control,last-modified,etag详细说明

http://blog.csdn.net/eroswang/article/details/8302191

[4] 在浏览器地址栏按回车、F5、Ctrl+F5刷新网页的区别

http://cloudbbs.org/forum.php?mod=viewthread&tid=15790

http://blog.csdn.net/yui/article/details/6584401

[5] Cache Control 與 ETag

https://blog.othree.net/log/2012/12/22/cache-control-and-etag/

[6] 缓存的故事

http://segmentfault.com/blog/animabear/1190000000375344

[7] Google的PageSpeed网站优化理论中提到使用Etag可以减少服务器负担

https://developers.google.com/speed/docs/pss/AddEtags

[8] yahoo的Yslow法则中则提示谨慎设置Etag

http://developer.yahoo.com/performance/rules.html#etags

[9] H5 缓存机制浅析 移动端 Web 加载性能优化

http://segmentfault.com/a/1190000004132566

[10] 网页性能: 缓存效率实践

http://www.w3ctech.com/topic/1648

[11] 透过浏览器看HTTP缓存

http://www.cnblogs.com/skylar/p/browser-http-caching.html

[12] 浏览器缓存知识小结及应用

http://web.jobbole.com/84888/

[13] 大公司里怎样开发和部署前端代码?

http://zhihu.com/question/20790576/answer/32602154?utm_campaign=webshare&utm_source=weibo&utm_medium=zhihu

[14] 浏览器缓存机制详解

https://mangguo.org/browser-cache-mechanism-detailed/

发表在 Linux | 留下评论