nodejs + nginx + redis cluster 高并发解决方案

本文介绍了一种利用Node.js作为应用服务器、Nginx作为负载均衡反向代理以及Redis Cluster进行数据存储的高并发解决方案。通过数据分级、状态分离等策略提高系统的稳定性和响应能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

nodejs + nginx + redis cluster 高并发解决方案

nodejs :应用服务器。
nginx :负载均衡反向代理。
redis cluster : 非主从的集群方案。

背景:
每当我们的应用服务,在网络上有许许多多的用户时。我们首先考虑到的是,我们的服务器能否承载同一时间高吞吐量的处理,我们的应用服务器架构应该如何去搭建。本文就是作者自己对于高性能web服务器的部分见解。

一、数据。
针对于用户使用数据而言,我们应该会对数据进行分级。例如简单的两级,用户会经常访问的(例如自己的id,地理信息);用户不会经常访问的(例如历史订单)。因此我们设计系统时就应该去考虑消除冗余,让经常使用的数据有更多的访问速度资源,不会经常使用的数据尽可能少的速度资源。最通俗的做法就是,经常访问的放在内存中,不经常访问的放入持久层,当然,经常访问的也应该在持久层中存根,不过用户访问的时候会先去访问内存中的数据,看是否是自己需要的。

传统的java 处理办法是在service中加个变量,缺点:
1.服务器挂掉后,登录状态和会话数据丢失,体验差。
2.java虚拟机自身缺陷,存储空间有限,需要进行jvm优化。
3.丢失后不可恢复,风险大。

面对传统的缺陷应运而生的 redis 主从处理方案出现了,它支持双机热备,1台处理,1台备份,在一定程度上可以防止数据丢失,对的你没看错,是一定程度上。为什么,分析下,在高并发环境中,一次吞吐量很大,主redis 正在处理新数据的时候挂掉了,从redis能一定保证把最新的数据备份下来了么?很显然不可能,所以一定会丢失。而且一台redis如果和n台web服务器交互,压力是很大的,挂掉的概率,啧啧啧。当然后来出现了keepalived 做负载均衡的,一定程度上减少了服务器的压力,但是这种方案,始终是下策(为什么是下策,如果两台服务器都有对方没有的新数据,突然挂掉了。。。再或者承载keepalived的这太机器出了问题。。。。)。风险还是太大了。

于是出现了redis cluster --集群,集群首先考虑的就是数据最小丢失,因此,采用的是数据分片技术,每台redis上存储的都是不同的数据,redis越多,数据分离的越细,一次丢失内容更少,没有代理层,性能稳定。XXXX等等一大堆优势,就不说了。

二、服务器集群只做数据处理,不做状态维持。

数据处理是很消耗计算机资源的,而状态维持相对较少。因此,大多高性能服务器都做状态和数据分离。nginx就是用来做会话状态维持,如图,整个系统中只有一个nginx。而会话状态中的数据,存储在redis集群中。

这里有个梗,如之前所说redis集群中,数据是以分片的形式存储在几台redis中,如果我需要的数据所在的redis正好挂掉了,怎么办。这就需要架构师对应用层编码进行规范,如何规范,需要专门的人员进行编写这种redis数据,数据提取策略是,如果这个数据从redis中获取不到,则直接从数据库中再次读取,再存储进入redis。

例如session对象内存储的数据,存储了一个user(点到为止,看不懂这个的,还需要多写写代码)。

废话不说了,上nginx配置代码(nginx如何配置安装,百度有大巴高手写过,小弟也是抄抄,不敢多写):

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;   
    keepalive_timeout  65;

    # 集群服务器配置 
    upstream sxt.com{

        # weight 表示权重,其实就是被访问的概率。例如3002是3000的6倍是3001的3倍。
        server 127.0.0.1:3000 weight=1;
        server 127.0.0.1:3001 weight=2;
        server 127.0.0.1:3002 weight=6;

    }

    server {
    
        listen       80;
        server_name  localhost;
       
        location / {

            # 配置代理
            proxy_pass http://sxt.com;
            proxy_redirect default;

        }
       
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        
    }

}

作者只对跟负载均衡,反向代理相关的地方进行了注释。

这样配置之后,当访问nginx所在机器(例如192.168.1.200)的80端口时(http://192.168.1.200)

启动阿婆主的 nodejs服务器和 nginx服务器 并访问:





得到如上图中的结果:

发现---一共3次请求,3台nodejs服务器接受到的请求数目不相同。
一共请求了一个html 一个css文件和一个js文件。

这就是weight (权重)起到的作用。此时,面向客户的负载均衡和反向代理,已经部署完毕。由3台服务器共同承担一个定向地址的请求。

那么问题来了,如何知道这个用户是否登录过了呢?这个问题就是会话状态维持,会话状态实际上,是由session-cookies 来绑定维持的,做过移动的webView的同学应该都知道这个,所以,前端nginx和后端任意一台nodejs服务器都不用关心会话,因为这个数据是存储在redis集群上的,nodejs直接去集群上获取比对session-cookies数据,相同则登陆过,不同则没有登陆过,放心session-cookies是不会变的,因为用户是唯一与nginx进行交互的,只要nodejs或者如果java服务器程序猿,不去自己手动获取session对象,就能保证会话一致




搞定了nginx 和 nodejs应用服务器之后,接下来就是nodejs服务器获取redis集群的部分了。
配置redis集群的方式,本文就不详述了,百度好多meet分片的文章。其实就是修改conf中几个参数,再手动修改分片文件进行分片就可以。当然也可以命令分片。



笔者在自己的虚拟机里,配置并启动了三台redis,构建成了一个cluster集群。
分别是:
192.168.1.200:7000
192.168.1.200:7001
192.168.1.200:7002

接下来就是需要注意的地方:
cluster集群与主从的redis有很大出入的地方:
1,java代码中:

import java.util.HashSet;
import java.util.Set;


import redis.clients.jedis.HostAndPort;

import redis.clients.jedis.JedisCluster;

/***
 * 测试redis
 * @author sxt
 *
 */
public class TestJedis {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		// 集群地址
	    Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
	    jedisClusterNodes.add(new HostAndPort("192.168.1.200", 7000));  
	    jedisClusterNodes.add(new HostAndPort("192.168.1.200", 7001));  
	    jedisClusterNodes.add(new HostAndPort("192.168.1.200", 7002));  
		
	    // 实例化集群
		JedisCluster jedis = new JedisCluster(jedisClusterNodes);
		
		// 向集群中绑定值
		jedis.set("name","shixiaotian");
		// 从集群中获取值
		String result = jedis.get("name");
		// 输出结果
		System.out.println(result);
		
	}

}

如上图代码中所示,官方给出的最简单的获取方式中,cluster并没有让我们指定从哪台redis中获取数据。为什么?

redis cluster 采用的是数据分片技术,并没有热备份。每个数据都是存在固定的位置的,因此你访问任何一台机器,都会给你重新定向到存储你需要数据的那台redis上,所以不存在并发问题,因为,你横竖都得到这台机器上来。这与之前接触到的主从完全不一样,这里讲究的是分片后的最小丢失,主从讲究的是不丢失(想法总是很好的)。

因此,你完全不需要对cluster做负载均衡,集群自己处理(很赞,这才是合格的产品,屏蔽让别人觉得麻烦的东西,不需要自己去挂个代理了)。

nodejs中读取redis集群的方式也要进行相应的改变,为了区分两种的编码方式,下面都给出:


1.主从读取方式
//redis 链接
var redis   = require('redis');
var client  = redis.createClient('7000', '192.168.1.200');
// redis 链接错误
client.on("error", function(error) {
    console.log(error);
});

// 向特定的redis机器上绑定数据
cluster.set('foo', 'bar');
// 从特定redis上获取数据
cluster.get('foo', function (err, res) {
  
  console.log(res);

});

2.cluster集群获取方式:
// 注意,不一样的模块
var Redis = require('ioredis');

// 不一样的创建方式,多台获取,出来就是集群
var cluster = new Redis.Cluster(
    [{
      port: 7000,
      host: '192.168.1.200'
    }, {
      port: 7001,
      host: '192.168.1.200'
    }, {
      port: 7002,
      host: '192.168.1.200'
    }]
);
// 设置数据相同
cluster.set('foo', 'bar');
// 获取数据相同
cluster.get('foo', function (err, res) {
  
  console.log(res);
  
});

我们这里使用的是第二种方式,因为是cluster集群。


接下来,编写应用程序,所有使用到的session 数据,全部使用cluster中获取到的,或者存入的,即可。

对的。。你看见开篇第一章图上面的那个绿色的管子的么?有没有什么不一样。
<think>嗯,用户现在想在Windows上使用Node.js和Nginx搭建图床系统。之前他们问过在Windows上搭建图床的方法,我给出了Docker和PHPStudy的方案。现在用户的需求更具体了,明确要用Node.js和Nginx。首先,我需要回顾一下用户提供的引用内容。引用[1]提到用Node.js和兰空图床实现随机图,可能涉及Express框架和API调用。引用[2]是自己开发Node.js图床接口,存储图片在uploads文件夹。引用[3]是关于部署Node项目和Nginx配置。引用[4]提到用Nginx做静态资源转发,但担心服务器过期导致图片丢失,所以改用图床。 用户现在的需求是结合Node.js和Nginx在Windows上搭建图床。我需要考虑如何整合这两个工具。Node.js负责处理上传逻辑,Nginx作为反向代理和静态资源服务器。步骤应该是:先安装Node.js和Nginx,然后创建Node.js的上传接口,使用Express处理文件上传,保存到指定目录。接着配置Nginx来代理Node.js应用,并直接提供静态文件的访问。可能需要设置路由,比如上传请求走Node.js,而图片访问直接由Nginx处理。还要考虑文件存储的位置,确保Nginx有权限访问。另外,可能需要配置Nginx的静态资源路径,避免路径冲突。用户可能还需要持久化存储,所以需要指导如何设置正确的目录结构。用户之前的问题中提到了Docker和PHPStudy的方案,现在转向Node.js和Nginx,可能需要解释两者的优势,比如更灵活的控制和性能优化。同时,用户可能关心如何实现高可用性,或者如何扩展存储到云服务,但当前问题集中在本地搭建。需要检查是否有遗漏的步骤,比如安装依赖、处理跨域问题、设置正确的MIME类型,或者配置Nginx的缓存策略。此外,可能涉及安全设置,比如限制上传文件类型和大小,防止恶意上传。 最后,生成相关问题,帮助用户深入解决可能遇到的问题,比如如何配置HTTPS、优化上传性能、处理高并发,或者集成数据库管理图片信息。这些相关问题需要基于当前步骤中的关键点来设计。</think>### 使用Node.js + Nginx在Windows搭建图床系统的分步教程 #### 一、核心架构设计 1. **Node.js**:负责处理图片上传接口(Express框架) 2. **Nginx**:作为反向代理和静态资源服务器,提供图片访问加速[^3][^4] 3. **存储方案**:本地磁盘存储(可扩展至OSS/MinIO)[^2] --- #### 二、具体实现步骤 ##### 步骤1:安装必要软件 ```powershell # 安装Node.js(官网下载LTS版本) # 安装Nginx for Windows(官网下载ZIP包) # 解压Nginx到C:\nginx ``` ##### 步骤2:创建Node.js图床服务 1. **初始化项目** ```powershell mkdir C:\node-image-host && cd C:\node-image-host npm init -y npm install express multer uuid ``` 2. **编写app.js(核心上传接口)** ```javascript const express = require('express'); const multer = require('multer'); const { v4: uuidv4 } = require('uuid'); const path = require('path'); const app = express(); // 配置存储路径 const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'C:/nginx/html/uploads/') // 需与Nginx静态目录一致 }, filename: (req, file, cb) => { const ext = path.extname(file.originalname); cb(null, uuidv4() + ext); // 生成唯一文件名 } }); const upload = multer({ storage }); // 上传接口 app.post('/upload', upload.single('image'), (req, res) => { res.json({ url: `http://localhost:8080/uploads/${req.file.filename}` }); }); app.listen(3000, () => { console.log('Node服务运行在:3000端口'); }); ``` ##### 步骤3:配置Nginx 1. **修改C:\nginx\conf\nginx.conf** ```nginx server { listen 8080; server_name localhost; # 反向代理Node服务 location /api { proxy_pass http://localhost:3000; proxy_set_header Host $host; } # 静态资源访问 location /uploads { alias html/uploads; autoindex on; expires 30d; # 缓存优化 } } ``` 2. **创建存储目录** ```powershell mkdir C:\nginx\html\uploads ``` ##### 步骤4:启动服务 ```powershell # 启动Node服务 node C:\node-image-host\app.js # 启动Nginx C:\nginx\nginx.exe ``` --- #### 三、功能验证 1. **测试上传(使用Postman)** - 发送POST请求到`http://localhost:8080/api/upload` - Body选择`form-data`,字段名`image`并选择图片文件 - 响应示例: ```json { "url": "http://localhost:8080/uploads/3a7f3d8b-2c4f-4e1d-bd87-1c6d8e9f2a3d.png" } ``` 2. **访问图片** 浏览器直接打开返回的URL即可显示图片[^2] --- #### 四、系统优化建议 1. **安全增强** - 添加文件类型校验(限制jpg/png等格式) - 设置最大文件尺寸限制(通过`multer`的`limits`参数) 2. **性能优化** - 启用Nginx gzip压缩 - 添加CDN支持(如七牛云/阿里云OSS)[^4] --- #### 架构示意图 ``` 客户端 -> Nginx(8080) ├── /api/* -> Node.js(3000) # 处理上传 └── /uploads/* -> 直接返回静态文件 ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值