灿烂の日常
type: channel
link: https://www.handsomejg.com/
description: 嚯嚯
items: New API + CLI Proxy API Plus 中转站部署说明
items: dbswitch使用说明
items: 替换jar包中的class文件
items: RabbitMQ的使用
items: rabbitMQ安装和配置
items: 在linux系统中使用crontab备份MySQL远程数据库
items: 异步的八种实现方式
items: .NET中使用MinIO文件存储的常用操作方法
items: Nginx+SpringBoot实现负载均衡
items: sql语句优化的方法

New API + CLI Proxy API Plus 中转站部署说明
type: item
date: 2026-06-01T11:49:52+08:00
description: 最近折腾了一套自己的 AI 中转站，主要用到两个东西：New API 和 CLI Proxy API Plus。New API 负责统一管理渠道、模型、令牌、用户和日志；CLI Proxy API Plus 负责把一些 CLI/OAuth 类模型能力转换成 OpenAI 兼容接口（例如将chat gpt套餐转化成兼容接口提供给New API作为渠道使用）。以下是我自己整理的一套部署流程，尽量写成从零开始照着操作就能搭好的版本。 注意：文档里面的密码、密钥都用占位符，不要把真实密码直接写到博客里。功能描述简单来说，这套东西搭好后大概是这样：本地客户端 / Codex / 其他调用方 ↓ New API 统一入口 ↓ CLI Proxy API Plus ↓ 上游模型账号 / API Key / OAuth 登录态New API 主要做这些事：统一管理不同渠道。统一生成下游调用令牌。查看调用日志、用量、消耗。给不同用户、不同分组设置可用模型。对外暴露一个 OpenAI 兼容接口。CLI Proxy API Plus 主要做这些事：接收 OpenAI 兼容格式的请求。转发到 Codex、Claude、Gemini、OpenAI 兼容服务等上游。支持 API Key 和 OAuth 登录态。支持模型别名、模型转发、重试、管理面板等。我个人理解是： CLI Proxy API Plus 更像“底层转发器”，New API 更像“后台管理系统”。一、服务器准备我这里以一台普通云服务器为例，阿里云、腾讯云、雨云、RackNerd、Vultr 都差不多。1. 推荐配置如果只是自己用，配置不用太高：CPU：2 核 内存：2G 起步，4G 更舒服 硬盘：40G 起步 系统：Alibaba Cloud Linux / CentOS / Debian / Ubuntu 都可以 地区：尽量选择访问上游模型比较稳定的地区如果你后面要给多人使用，建议至少：CPU：2 核以上 内存：4G 以上 硬盘：60G 以上2. 需要开放的端口在云服务器安全组中开放以下端口：22 SSH 登录服务器 3000 New API 后台 8317 CLI Proxy API Plus 接口，按需开放 80 如果后面要配域名和 Nginx 443 如果后面要配 HTTPS注意：3306 MySQL 不建议对公网开放 6379 Redis 不建议对公网开放MySQL 和 Redis 给 Docker 内部用就行，不要随便暴露到公网。3. 登录服务器本地 Windows 可以用 Windows Terminal、XShell、FinalShell、Termius。SSH 登录方式如下：ssh root@你的服务器公网IP如果 SSH 端口不是 22，比如改成了 2222：ssh root@你的服务器公网IP -p 2222登录后大概会看到：[root@xxx ~]#这就说明已经进服务器了。二、安装基础环境先安装一些常用工具：yum install -y curl wget git vim unzip有些系统没有 yum，比如 Debian/Ubuntu，可以用：apt update apt install -y curl wget git vim unzip1. 安装 Docker直接使用官方安装脚本：curl -fsSL https://get.docker.com | bash启动 Docker：systemctl enable docker systemctl start docker检查 Docker 是否正常：docker version docker compose version能看到版本号就可以。2. 创建统一目录和 Docker 网络我建议把所有中转站相关的东西都放在 /opt/ai-gateway 下，后期找起来方便。mkdir -p /opt/ai-gateway cd /opt/ai-gateway创建一个公共 Docker 网络，让 New API 可以直接通过容器名访问 CLI Proxy API Plus：docker network create ai-gateway-network如果提示已经存在，不用管，继续下一步。三、部署 New APINew API 官方镜像是：calciumion/new-api:latest官方说明中支持 SQLite、MySQL、PostgreSQL，个人测试可以用 SQLite，但是长期使用建议直接 MySQL。 这里我用 MySQL + Redis + New API 的方式部署。1. 创建目录mkdir -p /opt/ai-gateway/new-api cd /opt/ai-gateway/new-api2.…

dbswitch使用说明
type: item
date: 2024-08-26T17:03:00+08:00
description: 最近又来了个棘手的项目，时间紧任务重，要基于现有的软件，把MySQL数据库完全复制到Oracle数据库，查了相关数据库迁移的资料，最后决定使用dbswitch，以下是我使用时的一些经验。gitee地址：dbswitch功能描述一句话，dbswitch工具提供源端数据库向目的端数据库的批量迁移同步功能，支持数据的全量和增量方式同步。包括：结构迁移支持字段类型、主键信息、建表语句等的转换，并生成建表SQL语句。支持基于正则表达式转换的表名与字段名映射转换。数据同步。基于JDBC的分批次读取源端数据库数据，并基于insert/copy方式将数据分批次写入目的数据库。支持有主键表的 增量变更同步 （变化数据计算Change Data Calculate）功能(千万级以上数据量的性能尚需在生产环境验证)使用步骤及注意事项1.直接拉取代码，或者下载zip包到桌面2.双击build.cmd脚本文件即可编译打包JDK:>=1.8 （建议用JDK 1.8）maven:>=3.6要配置对应的环境遍历，按win+r，打开cmd，输入mvn -v可以出现maven版本号即可3.打包完成后，在同目录（target文件夹）下会出现：dbswitch-release-1.9.9.tar.gz压缩包，直接解压4.编辑dbswitch-release-1.9.9\conf文件夹下的application.yml文件server: port: 9088 spring: application: name: dbswitch-admin tomcat: uri-encoding: UTF-8 max-http-header-size: 8096 mvc: throw-exception-if-no-handler-found: false static-path-pattern: /statics/** datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://你自己的数据库ip地址:3306/zhwy_fx?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=30000 username: 账号 password: 密码 validation-query: SELECT 1 test-on-borrow: true flyway: locations: classpath:db/migration baseline-on-migrate: true table: DBSWITCH_SCHEMA_HISTORY enabled: true mybatis: configuration: lazy-loading-enabled: true aggressive-lazy-loading: false map-underscore-to-camel-case: true #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #注意此处地址就是解压后的dbswitch-release-1.9.9文件夹中drivers的地址 dbswitch: configuration: drivers-base-path: C:\Users\22727\Desktop\dbswitch-release-1.9.9\drivers注意配置数据库的url，username，password，还有驱动包的地址drivers-base-path5.找到bin目录中的startup.cmd文件，双击启动即可如果启动的时候报错，说你配置的数据库中缺少什么表（不影响启动），就打开如下文件复制sql执行下6.启动成功后在浏览器中输入地址：http://localhost:9088，默认账号密码：admin/1234567.配置连接将目标库和源库信息添加进去以下是我的相关配置可作为参考（MySQL库导入到Oracle库）源库（MySQL）配置：目标库（Oracle）配置：注意红框中内容，别写错了，配置完后可以测试下是否连接成功，如果没找到自己的驱动，也可以在【连接管理-驱动配置】中添加8.创建同步任务在【数据接入-任务管理】中创建任务，我的配置如下：在配置目标端时，注意在【同步前置执行SQL脚本】中执行以下内容：CREATE PROCEDURE RemoveNotNullConstraintsE…

替换jar包中的class文件
type: item
date: 2024-06-18T17:34:00+08:00
description: 没想到在2024年，我还要用这种方式去更新程序，其中的辛酸和踩过的坑就不多说了。这里推荐使用是winRar解压缩工具，我也试过其他解压缩工具，例如BandiZip，但都没效果（可能是我不会操作）准备jar包解压jar先将jar包的后缀名改为.zip,得到压缩包如图解压压缩包解压后得到文件夹：这个时候可以根据需要替换或者修改其中的文件，之后再将它打包为jar重新打包为jar在文件夹内部 全部选中文件然后打包，注意是文件夹内部，不然打出来的包可能会多出来一层打包配置注意：如果原来的jar包中依赖的有其他的jar,如图：需要将这些依赖的jar包排除在压缩文件队列中，不然会造成二次压缩：压缩后得到一个zip格式的压缩包：直接改后缀为.jar这样就可以运行了错误示例：依赖的jar被重复压缩会出现下面的报错

RabbitMQ的使用
type: item
date: 2024-03-06T17:32:00+08:00
description: 什么是MQ？MQ全称为Message Queue，即消息队列。“消息队列”是在消息的传输过程中保存消息的容器。也是在消息的传输过程中保存消息的容器。用于分布式系统之间进行通信。典型的：生产者、消费者模型。MQ本身就相当于一个中间件，用于生产方通过MQ与消费方之间的交互作用。RabbitMQ应用场景场景一 、解耦上面我们提到MQ本身就相当于一个中间件，用于生产方通过MQ与消费方之间的交互作用。让我们看一下传统模式和这种中间件模式的对比：传统模式：系统间耦合性太强，如图所示，系统A在代码中直接调用系统B和系统C的代码，如果将来D系统接入，系统A还需要修改代码，过于麻烦！中间件模式：​ 将消息写入消息队列，需要消息的系统自己从消息队列中订阅，从而系统A不需要做任何修改。场景二 、异步传统模式:​ 一些非必要的业务逻辑以同步的方式运行，太耗费时间中间件模式:​ 将消息写入消息队列，非必要的业务逻辑以异步的方式运行，加快响应速度场景三、削峰传统模式：​ 并发量大的时候，所有的请求直接怼到数据库，造成数据库连接异常中间件模式:​ 系统A慢慢的按照数据库能处理的并发量，从消息队列中慢慢拉取消息RabbitMQ的使用RabbitMQ是一个消息代理：它接受和转发消息。 你可以把它想象成一个邮政信箱RabbitMQ与邮局的主要区别是它不处理纸张，而是接受，存储和转发数据消息的二进制数据块。如何避免消息堆积？1） 采用workqueue，多个消费者监听同一队列。2）接收到消息以后，而是通过线程池，异步消费。如何避免消息丢失？1） 消费者的ACK机制。可以防止消费者丢失消息。但是，如果在消费者消费之前，MQ就宕机了，消息就没了？2）可以将消息进行持久化。要将消息持久化，前提是：队列、Exchange都持久化RabbitMQ提供了6种消息模型，但是第6种是RPC，并不是MQ，因此不学习。那么也就剩下5种，3、4、5这三种都属于订阅模型，只不过进行路由的方式不同。1.Simple-简单模型P（producer/ publisher）：生产者，一个发送消息的用户应用程序。 C（consumer）：消费者，消费和接收有类似的意思，消费者是一个主要用来等待接收消息的用户应用程序队列（红色区域）：rabbitmq内部类似于邮箱的一个概念。虽然消息流经rabbitmq和你的应用程序，但是它们只能存储在队列中。队列只受主机的内存和磁盘限制，实质上是一个大的消息缓冲区。许多生产者可以发送消息到一个队列，许多消费者可以尝试从一个队列接收数据。引入依赖我们将用Java编写两个程序;发送单个消息的生产者，以及接收消息并将其打印出来的消费者。我们将详细介绍Java API中的一些细节，这是一个消息传递的“Hello World”。我们将调用我们的消息发布者（发送者）Send和我们的消息消费者（接收者）Recv。发布者将连接到RabbitMQ，发送一条消息，然后退出。新建一个spring boot项目,使用spring 2和jdk 8,引入下面的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> <version>3.1.5</version> </dependency>新建一个连接工具类:package com.test.demo.util; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; /** * rabbitMQ连接类 * * @author jg * @since 2023/11/7 15:27 */ public class ConnectionUtil { /** * 建立与RabbitMQ的连接 * * @return Connection * @throws Exception 异常 */ public static Connection getConnection() throws Exception { //定义连接工厂 ConnectionFactory factory = new ConnectionFactory(); //设置服务地址 factory.setHost("你的IP地址"); //端口,rabbitmq默认端口号为5672,阿里云等服务器记得开启防火墙和安全组 factory.setPort(5672); //设置账号信息，用户名、密码、vhost factory.setUsername("username"); factory.setPassword…

rabbitMQ安装和配置
type: item
date: 2023-11-08T17:30:00+08:00
description: 1、RabbitMQ简介官网：https://www.rabbitmq.com/RabbitMQ是一个开源的遵循AMQP协议实现的基于Erlang语言编写，支持多种客户端（语言），用于在分布式系统中存储消息，转发消息，具有高可用高可扩性，易用性等特征。2.下载,安装,启动下载地址：https://www.rabbitmq.com/download.html选择对应的系统版本点击下载，下载后会得到.rpm文件下载ErlangRabbitMQ是采用 Erlang语言开发的，所以系统环境必须提供 Erlang环境，需要是安装 ErlangErlang和RabbitMQ版本对照：https://www.rabbitmq.com/which-erlang.html这里安装最新版本3.12.8的RabbitMQ，对应的Erlang版本推荐26.1.x，我们下载erlang-26.1.2-1.el9.x86_64.rpm下载地址：https://packagecloud.io/rabbitmq/erlang/packages/el/9/erlang-26.1.2-1.el9.x86_64.rpm?distro_version_id=240其中的el9表示Red Hat 9.x，即CentOS 9.x，因为我没找到7.x的版本，所以暂时用这个点击右上角下载即可得到.rpm文件安装Erlang首先将下载好的文件上传到服务器，创建一个文件夹用来存放文件mkdir -p /usr/rabbitmq再利用xftp工具将上述下载的两个.rpm文件上传到服务器的刚创建的文件夹中然后切换到/usr/rabbitmq目录，解压安装erlang# 解压 rpm -Uvh erlang-26.1.2-1.el9.x86_64.rpm # 安装 yum install -y erlang安装完成后输入如下指令查看版本号# 查看版本号 erl -v安装RabbitMQ在RabiitMQ安装过程中需要依赖socat插件，首先安装该插件# 安装socat插件 yum install -y socat然后解压安装RabbitMQ的安装包# 解压 rpm -Uvh rabbitmq-server-3.12.8-1.el8.noarch.rpm # 安装 yum install -y rabbitmq-server启动RabbitMQ服务# 启动rabbitmq systemctl start rabbitmq-server # 查看rabbitmq状态 systemctl status rabbitmq-server显示如下信息则启动成功：其他命令：# 设置rabbitmq服务开机自启动 systemctl enable rabbitmq-server # 关闭rabbitmq服务 systemctl stop rabbitmq-server # 重启rabbitmq服务 systemctl restart rabbitmq-server3、RabbitMQ Web管理界面及授权操作安装启动RabbitMQ Web管理界面默认情况下，rabbitMQ没有安装web端的客户端软件，需要安装才可以生效# 打开RabbitMQWeb管理界面插件 rabbitmq-plugins enable rabbitmq_management然后我们打开浏览器，访问服务器公网ip:15672（注意打开阿里云安全组以及防火墙的15672端口），就可以看到管理界面浏览器访问：rabbitmq有一个默认的账号密码guest，但该情况仅限于本机localhost进行访问，所以需要添加一个远程登录的用户添加远程用户# 添加用户 rabbitmqctl add_user 用户名 密码 # 设置用户角色,分配操作权限 rabbitmqctl set_user_tags 用户名 角色 # 为用户添加资源权限(授予访问虚拟机根节点的所有权限) rabbitmqctl set_permissions -p / 用户名 ".*" ".*" ".*"角色有四种：administrator：可以登录控制台、查看所有信息、并对rabbitMQ进行管理monToring：监控者；登录控制台，查看所有信息policymaker：策略制定者；登录控制台指定策略managment：普通管理员；登录控制这里创建用户admin，密码123456，设置administrator角色，赋予所有权限创建完成后，访问服务器ip:15672进行登录，然后便可进入到后台其他指令：# 修改密码 rabbitmqctl change_ password 用户名 新密码 # 删除用户 rabbitmqctl delete_user 用户名 # 查看…

在linux系统中使用crontab备份MySQL远程数据库
type: item
date: 2023-07-14T13:55:00+08:00
description: 最近公司其他项目组出现了一次生产事故，导致那个项目的近几个月数据全部丢失，好在有纸质资料作为数据存根，为此我们几个组加班加点手动录入数据苦不堪言。那之后各项目都要求定时备份数据库，所以我整理了我在使用MySQL备份远程数据库(centOS)的相关步骤。系统环境：1.centOS72.MySQL 8.0.31创建脚本文件创建数据库备份存放的文件夹和脚本文件，如图：写入脚本打开刚创建好的backup_mysql.sh文件，将以下内容写入进去：#!/bin/bash # 定义备份文件保存路径 backup_property_dir="/home/database_Backup/property" backup_property_ac_dir="/home/database_Backup/property_ac" backup_property_config_dir="/home/database_Backup/property_config" backup_property_job_dir="/home/database_Backup/property_job" backup_property_manage_dir="/home/database_Backup/property_manage" # 转换日期 timestamp=$(date +%Y%m%d%H%M%S) year=${timestamp:0:4} month=${timestamp:4:2} day=${timestamp:6:2} hour=${timestamp:8:2} minute=${timestamp:10:2} second=${timestamp:12:2} formatted_date="${year}年${month}月${day}日_${hour}:${minute}:${second}" # 定义备份文件名 backup_property="$backup_property_dir/backup_property_$formatted_date.sql" backup_property_ac="$backup_property_ac_dir/backup_property_ac_$formatted_date.sql" backup_property_config="$backup_property_config_dir/backup_property_config_$formatted_date.sql" backup_property_job="$backup_property_job_dir/backup_property_job_$formatted_date.sql" backup_property_manage="$backup_property_manage_dir/backup_property_manage_$formatted_date.sql" # 定义 MySQL 连接参数 mysql_user="你的MySQL用户名" mysql_password="你的MySQL密码" # 定义要备份的数据库名称 property_database="property" property_ac_database="property_ac" property_config_database="property_config" property_job_database="property_job" property_manage_database="property_manage" # 删除七天前的备份文件 find /home/database_Backup/property* -type f -name "backup_property_*" -mtime +7 -exec rm {} \; find /home/database_Backup/property_ac* -type f -name "backup_property_ac_*" -mtime +7 -exec rm {} \; find /home/database_Backup/property_config* -type f -name "backup_property_config_*" -mtime +7 -exec rm {} \; find /home/database_Backup/property_job* -type f -name "backup_property_job_*" -mtime +7 -exec rm {} \; find /home/database_Backup/property_manage* -type f -name "…

异步的八种实现方式
type: item
date: 2023-05-18T09:17:38+08:00
description: 异步执行对于开发者来说并不陌生，在实际的开发过程中，很多场景多会使用到异步，相比同步执行，异步可以大大缩短请求链路耗时时间，比如：发送短信、邮件、异步更新等，这些都是典型的可以通过异步实现的场景。异步的八种实现方式线程ThreadFuture异步框架CompletableFutureSpring注解@AsyncSpring ApplicationEvent事件消息队列第三方异步框架，比如Hutool的ThreadUtilGuava异步什么是异步？首先我们先看一个常见的用户下单的场景：在同步操作中，我们执行到 发送短信 的时候，我们必须等待这个方法彻底执行完才能执行 赠送积分 这个操作，如果 赠送积分 这个动作执行时间较长，发送短信需要等待，这就是典型的同步场景。实际上，发送短信和赠送积分没有任何的依赖关系，通过异步，我们可以实现赠送积分和发送短信这两个操作能够同时进行，比如：这就是所谓的异步，是不是非常简单，下面就说说异步的几种实现方式吧。1. 线程异步public class AsyncThread extends Thread { @Override public void run() { System.out.println("Current thread name:" + Thread.currentThread().getName() + " Send email success!"); } public static void main(String[] args) { AsyncThread asyncThread = new AsyncThread(); asyncThread.run(); } }当然如果每次都创建一个Thread线程，频繁的创建、销毁，浪费系统资源，我们可以采用线程池：private ExecutorService executorService = Executors.newCachedThreadPool(); public void fun() { executorService.submit(new Runnable() { @Override public void run() { log.info("执行业务逻辑..."); } }); }可以将业务逻辑封装到Runnable或Callable中，交由线程池来执行。2. Future异步@Slf4j public class FutureManager { public String execute() throws Exception { ExecutorService executor = Executors.newFixedThreadPool(1); Future<String> future = executor.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println(" --- task start --- "); Thread.sleep(3000); System.out.println(" --- task finish ---"); return "this is future execute final result!!!"; } }); //这里需要返回值时会阻塞主线程 String result = future.get(); log.info("Future get result: {}", result); return result; } @SneakyThrows public static void main(String[] args) { FutureManager manager = new FutureManager(); manager.execute(); } }输出结果： --- task start --- --- task finish --- Future get result: this is future execute final result!!!Future的不足之处Future的不足之处的包括以下几点：无法被动接收异步任务的计算结果：虽然我们可以主动将异步任务提交给线程池中的线程来执行，但是待异步任务执行结束之后，主线程无法得到任务完成与否的通知，它需要通过get方法主动获取任务执行的结果。Future件彼此孤立：有时某一个耗时很长的异步任务执行结束之后，你想利用它返回的结果再做进一步的运算，该运算也会是一个异步任务，两者之间的关系需要程序开发人员手动进行绑定赋予，Future并不能将其形成一个任务流（pipeline）…

.NET中使用MinIO文件存储的常用操作方法
type: item
date: 2022-12-23T17:29:00+08:00
description: 本篇内容主要记录.NET中使用MinIO文件存储的常用方法操作类，有关MioIO的概念和优缺点就不写了，百度都有。MinIO文件服务器的搭建请查看：Java集成MinIO，项目中使用NuGet搜索MinIO进行安装即可。using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using Minio; using Minio.DataModel; using Minio.Exceptions; namespace ConsoleApplication1 { public static class MinioHelper { static readonly string _endPoint = "127.0.0.1:9001"; static readonly string _accessKey = "minioadmin"; static readonly string _secretKey = "minioadmin"; static readonly bool _isSSL = false; private static readonly MinioClient _minioClient = new MinioClient() .WithEndpoint(_endPoint) .WithCredentials(_accessKey,_secretKey) .WithSSL(_isSSL) .Build(); /// /// 创建minio客户端连接 /// /// 127.0.0.1:9001 /// minioadmin /// minioadmin /// 是否是http /// <returns></returns> public static MinioClient Create(string endPoint, string accessKey, string secretKey, bool withSsl = false) { MinioClient client = new MinioClient() .WithEndpoint(endPoint) .WithCredentials(accessKey, secretKey); if (withSsl) { client = client.WithSSL(); } return client.Build(); } #region 操作存储桶 /// /// 创建存储桶 /// <example > /// /// MinioHelper.MakeBucket(minio, buckName).Wait(); /// /// </example> /// /// 存储桶名称 /// 可选参数 /// <returns ></returns > public static Task CreateBucket(string bucketName, string loc = "us-east-1") { try { bool found = BucketExists(bucketName); if (found) { throw new Exception($"存储桶[{bucketName}]已存在"); } MakeBucketArgs args = new MakeBucketArgs() .WithBucket(bucketName) .WithLocation(loc); return _minioClient.MakeBucketAsync(args); } catch (Exception e) { throw new Exception(e.Message); } } /// /// 校验桶是否存在,如果不存在则报错 /// <example> /// 调用示例 /// /// bool exists = MinioHelper.BucketExists(minio, buckName); /// /// </example> /// /// /// <exception cref="Exception"></exception> public static void CheckBucket(string bucketName) { bool exists = BucketExists(bucketName); if (!exists) { throw new BucketNotFoundException(bucketName, "存储桶不存在"); } } /// ///…

Nginx+SpringBoot实现负载均衡
type: item
date: 2022-09-05T15:07:00+08:00
description: 在介绍Nginx的负载均衡实现之前，先简单的说下负载均衡的分类，主要分为硬件负载均衡和软件负载均衡，硬件负载均衡是使用专门的软件和硬件相结合的设备，设备商会提供完整成熟的解决方案，比如F5，在数据的稳定性以及安全性来说非常可靠，但是相比软件而言造价会更加昂贵；软件的负载均衡以Nginx这类软件为主，实现一种消息队列分发机制。简单来说所谓的负载均衡就是把很多请求进行分流，将他们分配到不同的服务器去处理。比如我有3个服务器，分别为A、B、C，然后使用Nginx进行负载均衡，使用轮询策略，此时如果收到了9个请求，那么会均匀的将这9个请求分发给A、B、Cf服务器，每一个服务器处理3个请求，这样的话我们可以利用多台机器集群的特性减少单个服务器的压力。Nginx实现负载均衡的示例图:负载均衡策略NGINX开源支持四种负载平衡方法，而NGINX Plus又增加了两种方法。1.Round Robin: 对所有的请求进行轮询发送请求，默认的分配方式。nginx.conf 配置示例:upstream jiangguo { server www.handsomejg.com; server www.handsomejg2.com; }注:上面的域名也可以用IP替代。2.Least Connections：以最少的活动连接数将请求发送到服务器，同样要考虑服务器权重。nginx.conf 配置示例:upstream jiangguo { least_conn; server www.handsomejg.com; server www.handsomejg2.com; }3.IP Hash : 发送请求的服务器由客户机IP地址决定。在这种情况下，使用IPv4地址的前三个字节或整个IPv6地址来计算散列值。该方法保证来自相同地址的请求到达相同的服务器，除非该服务器不可用。upstream jiangguo { ip_hash; server www.handsomejg.com; server www.handsomejg2.com; }4.Generic Hash: 请求发送到的服务器由用户定义的键决定，该键可以是文本字符串、变量或组合。upstream jiangguo { hash $request_uri consistent; server www.handsomejg.com; server www.handsomejg2.com; }5.Least Time (NGINX Plus only) – 对于每个请求，NGINX Plus选择具有最低平均延迟和最低活动连接数的服务器，其中最低平均延迟是根据包含least_time指令的下列参数计算的:header ： 从服务器接收第一个字节的时间。 last_byte： 从服务器接收完整响应的时间。 last_byte inflight：从服务器接收完整响应的时间。 upstream jiangguo { least_time header; server www.handsomejg.com; server www.handsomejg2.com; }6.Random：每个请求将被传递到随机选择的服务器。如果指定了两个参数，首先，NGINX根据服务器权重随机选择两个服务器，然后使用指定的方法选择其中一个。least_conn ：活动连接的最少数量 least_time=header (NGINX Plus)：从服务器接收响应标头的最短平均时间 ($upstream_header_time)。 least_time=last_byte (NGINX Plus) ：从服务器接收完整响应的最短平均时间（$upstream_response_time）。 upstream jiangguo { random two least_time=last_byte; server www.handsomejg.com; server www.handsomejg2.com; }环境准备依赖JDK1.8以上的版本；依赖Nginx环境；首先我们下载这个项目，输入:mvn clean package 将项目进行打包为jar文件,然后将application.properties和此jar项目放在一个文件夹中，然后复制该文件夹(这里为了清晰所以进行复制，实际不复制更改端口重启也行)，修改复制文件夹application.properties的端口，比如改为8086。Nginx 配置我们找到nginx的配置文件nginx.conf，该配置在nginx/conf/nginx.conf目录下，然后我们来修改该配置，新增如下配置:upstream pancm{ server 127.0.0.1:8085; server 127…

sql语句优化的方法
type: item
date: 2022-07-14T16:25:12+08:00
description: 1.对查询进行优化，应尽量避免全表扫描，首先应考虑在 where 及 order by 涉及的列上建立索引。2.应尽量避免在 where 子句中使用!=或<>操作符，否则将引擎放弃使用索引而进行全表扫描。3.应尽量避免在 where 子句中对字段进行 null 值判断，否则将导致引擎放弃使用索引而进行全表扫描，如：select id from t where num is null 可以在num上设置默认值0，确保表中num列没有null值，然后这样查询：select id from t where num=0 4.应尽量避免在 where 子句中使用 or 来连接条件，否则将导致引擎放弃使用索引而进行全表扫描，如：select id from t where num=10 or num=20 可以这样查询：select id from t where num=10 union all select id from t where num=20 5.下面的查询也将导致全表扫描：select id from t where name like '%abc%' 若要提高效率，可以考虑全文检索。6.in 和 not in 也要慎用，否则会导致全表扫描，如：select id from t where num in(1,2,3) 对于连续的数值，能用 between 就不要用 in 了：select id from t where num between 1 and 3 7.如果在 where 子句中使用参数，也会导致全表扫描。因为SQL只有在运行时才会解析局部变量，但优化程序不能将访问计划的选择推迟到运行时；它必须在编译时进行选择。然而，如果在编译时建立访问计划，变量的值还是未知的，因而无法作为索引选择的输入项。如下面语句将进行全表扫描：select id from t where num=@num 可以改为强制查询使用索引：select id from t with(index(索引名)) where num=@num 8.应尽量避免在 where 子句中对字段进行表达式操作，这将导致引擎放弃使用索引而进行全表扫描。如：select id from t where num/2=100 应改为:select id from t where num=100*2 9.应尽量避免在where子句中对字段进行函数操作，这将导致引擎放弃使用索引而进行全表扫描。如：select id from t where substring(name,1,3)='abc'--name以abc开头的id select id from t where datediff(day,createdate,'2005-11-30')=0--'2005-11-30'生成的id 应改为:select id from t where name like 'abc%' select id from t where createdate>='2005-11-30' and createdate<'2005-12-1' 10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算，否则系统将可能无法正确使用索引。11.在使用索引字段作为条件时，如果该索引是复合索引，那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引，否则该索引将不会被使用，并且应尽可能的让字段顺序与索引顺序相一致。12.不要写一些没有意义的查询，如需要生成一个空表结构：select col1,col2 into #t from t where 1=0 这类代码不会返回任何结果集，但是会消耗系统资源的，应改成这样：create table #t(...) 13.很多时候用 exists 代替 in 是一个好的选择：select num from a where num in(select num from b) 用下面的语句替换：select num from a where exists(select 1 from b where num=a.num) 14.并不是所有索引对查询都有效，SQL是根据表中数据来进行查询优化的，当索引列有大量数据重复时，SQL查询可能不会去利用索引，如一表中有字段sex，male、female几乎各一半，那么即使在sex上建了索引也对查询效率起不了作用。15.索引并不是越多越好，索引固然可以提高相应的 select 的效率，但同时也降低了 insert 及 update 的效率，因为 insert 或 update 时有可能会重建索引，所以怎样建索引需要慎重考虑，视具体情况而定。一个表的索引数最好不要超过6个，若太多则应考虑一些不常使用到的列上建的索…