0%

不清楚阿里大于的,可参考我的上篇文章【短信验证码之阿里大于】

这是一个独立存在的工程, 和其他工程没有任何业务耦合,专门用来接收参数并发送短信

引入阿里大于SDK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.5</version>
</dependency>
</dependencies>

修改SmsDemo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package top.zhenganwen.sms

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class SmsUtil {

//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";

//在application.properties中配置AK
@Autowired
private Environment environment;

//发送短信
public SendSmsResponse sendSms(String mobile,String signName,String templateCode,String param) throws ClientException {

//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");

//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", environment.getProperty("accessKeyId"), environment.getProperty("accessKeySecret"));
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);

//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(mobile);
//必填:短信签名-可在短信控制台中找到
request.setSignName(signName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(templateCode);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(param);

//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");

//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");

//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

return sendSmsResponse;
}
}

创建引导类

1
2
3
4
5
6
7
8
9
10
11
12
package top.zhenganwen.sms;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
  • 添加配置文件application.properties
1
2
3
4
server.port=9090
spring.activemq.broker-url=tcp://47.98.xx.xx:61616
accessKeyId=xxx
accessKeySecret=xxx

创建消息监听类

  • 当有消息(包含要发送的手机号、变量参数)入队时,调用阿里大于短信服务接口进行短信的发送
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package top.zhenganwen.sms;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;


import java.util.Map;

@Component
public class SmsSenderListener {

@Autowired
private SmsUtil smsUtil;

@JmsListener(destination = "sms")
public void sendSms(Map<String,String> map) {
try {
SendSmsResponse response = smsUtil.sendSms(map.get("mobile"),
map.get("signName"),
map.get("templateCode"),
map.get("param"));
System.out.println(response.getCode());
System.out.println(response.getMessage());
} catch (ClientException e) {
e.printStackTrace();
}
}
}

创建测试工程

引导类

1
2
3
4
5
6
7
8
9
10
11
12
package top.zhenganwen.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
  • 添加配置文件
1
2
server.port=8080
spring.activemq.broker-url=tcp://47.98.xx.xx:61616

ActiveMQ调用微服务

  • 模拟用户请求注册,调用微服务发送验证码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package top.zhenganwen.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class QueueController {

@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;

@RequestMapping("/sendMessage")
public void sendMessage() {
Map<String, String> map = new HashMap<String, String>();
map.put("mobile","xxx");
map.put("signName","阿文");
map.put("templateCode", "SMS_137666550");
map.put("param","{\"code\":\"123456\"}");
jmsMessagingTemplate.convertAndSend("sms",map);
}
}

Jedis开发redis单机和集群

redis客户端依赖

1
2
3
4
5
6
 <!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
</dependency>

redis单机

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void testJedisPool() {
//config the properties of jedis pool
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(50);
poolConfig.setMinIdle(10);

JedisPool jedisPool = new JedisPool(poolConfig,"192.168.25.128",6379);

Jedis jedis = jedisPool.getResource();
jedis.set("age", "20");
System.out.println(jedis.get("age")); //20
}

redis集群

前提是你已经搭建好了redis集群——>搭建详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testJedisCluster() {
Set cluster = new HashSet();
cluster.add(new HostAndPort("192.168.25.128", 7001));
cluster.add(new HostAndPort("192.168.25.128", 7002));
cluster.add(new HostAndPort("192.168.25.128", 7003));
cluster.add(new HostAndPort("192.168.25.128", 7004));
cluster.add(new HostAndPort("192.168.25.128", 7005));
cluster.add(new HostAndPort("192.168.25.128", 7006));

JedisCluster jedisCluster = new JedisCluster(cluster);
jedisCluster.set("blog", "www.zhenganwen.tech");
System.out.println(jedisCluster.get("blog"));
}

Jedis客户端接口的抽取

  • 在开发过程中,并不需要redis集群来缓解高并发,因此常常使用一个redis服务器做测试。那由上文可知,操作redis单机和redis集群的代码是不一样的,前者通过创建的Jedis对象,后者通过JedisCluster对象,那产品上线时岂不是要改代码?

    面向接口编程

  • 上述问题中,虽然操作redis数据库的对象不一样,但他们有共同的API,这时我们应该抽取出一个jedis客户端接口,只要求它提供操作redis数据库的方法而并不关心其具体实现,以达到解耦的效果。

    具体实现

  • 接口的抽取
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public interface JedisClient {

    String set(String key, String value);
    String get(String key);
    Boolean exists(String key);
    Long expire(String key, int seconds);
    Long ttl(String key);
    Long incr(String key);
    Long hset(String key, String field, String value);
    String hget(String key, String field);
    Long hdel(String key, String... field);
    }
  • 单机版
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    public class JedisClientPool implements JedisClient {

    public JedisPool getJedisPool() {
    return jedisPool;
    }

    public void setJedisPool(JedisPool jedisPool) {
    this.jedisPool = jedisPool;
    }

    private JedisPool jedisPool;

    @Override
    public String set(String key, String value) {
    Jedis jedis = jedisPool.getResource();
    String result = jedis.set(key, value);
    jedis.close();
    return result;
    }

    @Override
    public String get(String key) {
    Jedis jedis = jedisPool.getResource();
    String result = jedis.get(key);
    jedis.close();
    return result;
    }

    @Override
    public Boolean exists(String key) {
    Jedis jedis = jedisPool.getResource();
    Boolean result = jedis.exists(key);
    jedis.close();
    return result;
    }

    @Override
    public Long expire(String key, int seconds) {
    Jedis jedis = jedisPool.getResource();
    Long result = jedis.expire(key, seconds);
    jedis.close();
    return result;
    }

    @Override
    public Long ttl(String key) {
    Jedis jedis = jedisPool.getResource();
    Long result = jedis.ttl(key);
    jedis.close();
    return result;
    }

    @Override
    public Long incr(String key) {
    Jedis jedis = jedisPool.getResource();
    Long result = jedis.incr(key);
    jedis.close();
    return result;
    }

    @Override
    public Long hset(String key, String field, String value) {
    Jedis jedis = jedisPool.getResource();
    Long result = jedis.hset(key, field, value);
    jedis.close();
    return result;
    }

    @Override
    public String hget(String key, String field) {
    Jedis jedis = jedisPool.getResource();
    String result = jedis.hget(key, field);
    jedis.close();
    return result;
    }

    @Override
    public Long hdel(String key, String... field) {
    Jedis jedis = jedisPool.getResource();
    Long result = jedis.hdel(key, field);
    jedis.close();
    return result;
    }

    }
  • 集群版
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    public class JedisClientCluster implements JedisClient {

    private JedisCluster jedisCluster;

    @Override
    public String set(String key, String value) {
    return jedisCluster.set(key, value);
    }

    @Override
    public String get(String key) {
    return jedisCluster.get(key);
    }

    @Override
    public Boolean exists(String key) {
    return jedisCluster.exists(key);
    }

    @Override
    public Long expire(String key, int seconds) {
    return jedisCluster.expire(key, seconds);
    }

    @Override
    public Long ttl(String key) {
    return jedisCluster.ttl(key);
    }

    @Override
    public Long incr(String key) {
    return jedisCluster.incr(key);
    }

    @Override
    public Long hset(String key, String field, String value) {
    return jedisCluster.hset(key, field, value);
    }

    @Override
    public String hget(String key, String field) {
    return jedisCluster.hget(key, field);
    }

    @Override
    public Long hdel(String key, String... field) {
    return jedisCluster.hdel(key, field);
    }

    public JedisCluster getJedisCluster() {
    return jedisCluster;
    }

    public void setJedisCluster(JedisCluster jedisCluster) {
    this.jedisCluster = jedisCluster;
    }
    }

    按需注入

  • 引用接口,利用@Autowired灵活注入实现类
    1
    2
    @Autowired
    private JedisClient jedisClient;
  • 开发时注入单机版客户端
    1
    2
    3
    4
    5
    6
    7
    8
    <!--单机版redis-->
    <bean class="tech.zhenganwen.elifang.common.jedis.JedisClientPool" id="jedisClientPool">
    <property name="jedisPool" ref="jedisPool"/>
    </bean>
    <bean class="redis.clients.jedis.JedisPool" id="jedisPool">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="6379"/>
    </bean>
  • 上线时切换成集群版客户端
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <!--redis集群-->
    <bean class="tech.zhenganwen.elifang.common.jedis.JedisClientCluster" id="clientCluster">
    <property name="jedisCluster" ref="jedisCluster"/>
    </bean>
    <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
    <constructor-arg name="nodes">
    <set>
    <bean class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="7001"/>
    </bean>
    <bean class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="7002"/>
    </bean>
    <bean class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="7003"/>
    </bean>
    <bean class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="7004"/>
    </bean>
    <bean class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="7005"/>
    </bean>
    <bean class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="192.168.25.128"/>
    <constructor-arg name="port" value="7006"/>
    </bean>
    </set>
    </constructor-arg>
    </bean>

在service中增加redis缓存

  • 原来每次调用服务都从数据库查询:
    1
    2
    3
    4
    5
    6
    7
    8
    public Collection<TbContent> getContentListByCatId(long categoryId) {

    TbContentExample example = new TbContentExample();
    TbContentExample.Criteria criteria = example.createCriteria();
    criteria.andCategoryIdEqualTo(categoryId);
    List<TbContent> tbContents = tbContentMapper.selectByExampleWithBLOBs(example);
    return tbContents;
    }
  • 现在为了减少数据库的压力和提高查询效率需要借助于redis缓存:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //根据分类的id查询内容
    public Collection<TbContent> getContentListByCatId(long categoryId) {
    /**
    *查询数据库前看缓存中是否已存在,不应该让操作缓存时抛出的异常影响查询流程因此需要try-catch
    */
    try {
    String contentsJson = jedisClient.hget(CONTENT_LIST, categoryId + "");
    if (StringUtils.isNotBlank(contentsJson)) {
    return JsonUtils.jsonToList(contentsJson,TbContent.class);
    }
    } catch (Exception e) {
    e.printStackTrace();
    }

    TbContentExample example = new TbContentExample();
    TbContentExample.Criteria criteria = example.createCriteria();
    criteria.andCategoryIdEqualTo(categoryId);
    List<TbContent> tbContents = tbContentMapper.selectByExampleWithBLOBs(example);

    /**
    将数据库中查出的放入缓存
    */
    try {
    //使用哈希数据类型,key为所有的内容,field为内容分类的id
    jedisClient.hset("CONTENT_LIST", categoryId + "", JsonUtils.objectToJson(tbContents));
    } catch (Exception e) {
    e.printStackTrace();
    }

    return tbContents;
    }

    缓存同步

  • 上述方法存在缺陷:如果数据库中content表中的数据发生改变,该方法无从知晓,仍旧从缓存中查询数据。因此我们需要在对content表进行增删改操作时将缓存中对应的hash中的field删除以达到缓存同步:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @Override
    //增加内容的方法
    public E3Result addContent(TbContent tbContent) {
    try {
    tbContent.setCreated(new Date());
    tbContent.setUpdated(new Date());
    tbContentMapper.insert(tbContent);
    /**
    * 缓存同步,因为这里是按内容分类来增加内容,因此没必要删除所有的内容缓存,只需将某个分类下的内容删除即可
    */
    jedisClient.hdel(CONTENT_LIST, tbContent.getCategoryId().toString());
    return E3Result.ok();
    } catch (Exception e) {
    e.printStackTrace();
    return E3Result.build(500, "添加失败!");
    }
    }

什么是Nginx?

Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。


应用场景

  • http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。

  • 虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。

    例如搭建个人博客时若独占一台主机未免有些浪费,这时可以将多个I域名绑定一个IP地址(主机),在主机上使用Nginx区分访问该主机的域名并转发到相应的博客服务器上。

  • 3、反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。


Nginx安装

要求的安装环境

  • 需要安装gcc的环境。yum install gcc-c++

  • 第三方的开发包

    • PCRE。PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库。nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库。

      1
      2
      3
      4
      5
      yum install -y pcre pcre-devel
      ````
      + zlib。zlib库提供了很多种压缩和解压缩的方式,nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库
      ```
      yum install -y zlib zlib-devel
    • openssl。OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。

      nginx不仅支持http协议,还支持https(即在ssl协议上传输http)
      1
      yum install -y openssl openssl-devel

安装步骤

  1. 把nginx的源码包上传到linux系统
  2. 解压缩
    [root@localhost ~]# tar zxf nginx-1.8.0.tar.gz
  3. 使用configure命令创建一makeFile文件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ./configure \
    --prefix=/usr/local/nginx \
    --pid-path=/var/run/nginx/nginx.pid \
    --lock-path=/var/lock/nginx.lock \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --with-http_gzip_static_module \
    --http-client-body-temp-path=/var/temp/nginx/client \
    --http-proxy-temp-path=/var/temp/nginx/proxy \
    --http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
    --http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
    --http-scgi-temp-path=/var/temp/nginx/scgi

注意:启动nginx之前,上边将临时文件目录指定为/var/temp/nginx,需要在/var下创建temp及nginx目录

1
root@localhost ~]# mkdir /var/temp/nginx/client -p
  1. make
  2. make install

启动和关闭

  • 启动

    1
    2
    进入sbin目录
    [root@localhost sbin]# ./nginx
  • 关闭

    1
    2
    3
    [root@localhost sbin]# ./nginx -s stop
    推荐使用:
    [root@localhost sbin]# ./nginx -s quit
  • 重启

    1
    2
    3
    4
    重启nginx:
    1、先关闭后启动。
    2、刷新配置文件:
    [root@localhost sbin]# ./nginx -s reload

访问Nginx

默认是80端口。
注意:是否关闭防火墙。

  • 若显示欢迎页则启动成功。

反向代理

正向代理

局域网中的主机通过可以上网的代理服务器间接的上网,请求由无网的主机发出,代理主机将请求转发。——客户端

反向代理

用户请求发送到反向代理服务器,反向代理服务器决定哪台服务器提供服务。返回代理服务器不提供服务。只是将请求转发。——服务器端

Nginx实现反向代理

  • 两个域名指向同一台nginx服务器,用户访问不同的域名显示不同的网页内容。
    如两个域名是www.sian.com和www.sohu.com,nginx服务器使用虚拟机192.168.80.128(我的虚拟机上Linux的IP地址)

    1. 安装两个tomcat,分别运行在8080和8081端口(在server.xml中将port都改一下,避免冲突)。

    2. 启动两个tomcat。

    3. 在本地hosts文件中增加域名解析

      1
      2
      192.168.80.128 www.sina.com
      192.168.80.128 www.sohu.com
    4. 反向代理服务器的配置:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      upstream tomcat1{
      server 192.168.80.128:8080;
      }
      server {
      listen 80;
      server_name www.sohu.com;

      #charset koi8-r;

      #access_log logs/host.access.log main;

      location / {
      proxy_pass http://tomcat1; #根据域名转发到相应的服务器
      index index.html index.htm;
      }
      }

      upstream tomcat2 {
      server 192.168.80.128:8081;
      }
      server {
      listen 80;
      server_name www.sina.com;

      #charset koi8-r;

      #access_log logs/host.access.log main;

      location / {
      proxy_pass http://tomcat2;
      index index.html index.htm;
      }
      }
    5. 重新加载nginx配置文件

      [root@localhost nginx]# sbin/nginx -s reload

6.  访问www.sina.com、www.sohu.com

负载均衡

如果一个服务由多条服务器提供,需要把负载分配到不同的服务器处理,需要负载均衡。

1
2
3
4
upstream tomcat2 {
server 192.168.80.128:8081;
server 192.168.80.128:8082;
}
  • 可以根据服务器的实际情况调整服务器权重。权重越高分配的请求越多,权重越低,请求越少。默认是都是1(即各轮流一次)

    1
    2
    3
    4
    upstream tomcat2 {
    server 192.168.25.148:8081;
    server 192.168.25.148:8082 weight=2;
    }

Nginx的高可用

要实现nginx的高可用,需要实现备份机

什么是负载均衡高可用

  • nginx作为负载均衡器,所有请求都到了nginx,可见nginx处于非常重点的位置,如果nginx服务器宕机后端web服务将无法提供服务,影响严重
  • 为了屏蔽负载均衡服务器的宕机,需要建立一个备份机。主服务器和备份机上都运行高可用(High Availability)监控程序,通过传送诸如“I am alive”这样的信息来监控对方的运行状况。当备份机不能在一定的时间内收到这样的信息时,它就接管主服务器的服务IP并继续提供负载均衡服务;当备份管理器又从主管理器收到“I am alive”这样的信息时,它就释放服务IP地址,这样的主服务器就开始再次提供负载均衡服务

配置虚拟主机

就是在一台服务器启动多个网站。

  • 如何区分不同的网站:
    1. 域名不同
    2. 端口不同

通过端口区分不同虚拟机

  • 查看Nginx的配置文件(/usr/local/nginx/conf/nginx.conf)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    events {
    worker_connections 1024;
    }


    http {
    include mime.types;
    default_type application/octet-stream;

    #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    # '$status $body_bytes_sent "$http_referer" '
    # '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log logs/access.log main;

    sendfile on;
    #tcp_nopush on;
    #keepalive_timeout 0;
    keepalive_timeout 65;

    #gzip on;

    #一个server节点就是一个虚拟主机
    server {
    listen 80;
    server_name localhost;

    #charset koi8-r;

    #access_log logs/host.access.log main;
    #html是nginx安装目录下的html目录
    location / {
    root html;
    index index.html index.htm;
    }
    }
    }
  • 可以配置多个server,配置了多个虚拟主机。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
        server {
    listen 80;
    server_name localhost;

    #charset koi8-r;

    #access_log logs/host.access.log main;

    location / {
    root html;
    index index.html index.htm;
    }
    }
    server {
    listen 81;
    server_name localhost;

    #charset koi8-r;

    #access_log logs/host.access.log main;

    location / {
    root html-81;
    index index.html index.htm;
    }
    }

    + 重新加载nginx配置文件
    ```
    [root@localhost nginx]# sbin/nginx -s reload
    1
    2
    3
    +   在nginx/下创建html-81文件夹
    ```
    cp -r html html-81
  • 开放81端口

    1. 写入修改
      1
      /sbin/iptables -I INPUT -p tcp --dport 81 -j ACCEPT
    2. 保存修改
      1
      /etc/init.d/iptables save
    3. 重启防火墙
      1
      service iptables restart
  • 访问81端口


通过域名区分虚拟主机

一个域名对应一个ip地址,一个ip地址可以被多个域名绑定。

  • 本地测试可以修改hosts文件。
    修改window的hosts文件:(C:\Windows\System32\drivers\etc)
    可以配置域名和ip的映射关系,如果hosts文件中配置了域名和ip的对应关系,不需要走dns服务器。

  • 将内容修改如下
    #这是我虚拟机上linux的IP地址
    192.168.80.128 www.test1.com
    192.168.80.128 www.test2.com

  • 在nginx/下创建html-test1、html-test2文件夹

    1
    2
    cp -r html html-test1
    cp -r html html-test2
  • 在Nginx的配置文件/nginx/conf/nginx.conf增加虚拟主机

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    server {
    listen 80;
    server_name www.test1.com;

    #charset koi8-r;

    #access_log logs/host.access.log main;

    location / {
    root html-test1;
    index index.html index.htm;
    }
    }
    server {
    listen 80;
    server_name www.test2.com;

    #charset koi8-r;

    #access_log logs/host.access.log main;

    location / {
    root html-test2;
    index index.html index.htm;
    }
    }
  • 重新加载nginx配置文件

    1
    [root@localhost nginx]# sbin/nginx -s reload
  • 访问www.test1.com和www.test2.com