Leo的技术分享

记录开发的点滴

概览

当前 ChatGPT 大为流行,可以说是火爆全网。为了体验 ChatGPT,不少用户可能采用在代理网站充值的方式使用。
其实,开源社区已有不少 ChatGPT 的使用方案,例如,https://poe.com/ 提供基于多种模型的智能问答服务,可以供用户直接免费体验使用。

ChatGPT-Next-Web 则提供一键部署个人专属 ChatGPT 网页应用的方案,只需要一个 OpenAI API Key,使用起来省钱又省力。

关于 OpenAI API Key,请读者通过自己的渠道获取,本文不作介绍。

部署

准备工作

  • OpenAI API Key:一个有剩余额度,且没过期的 API Key,用于访问 OpenAI API 接口
  • GitHub 账号:用于登录 Vercel,进行网页应用的部署
  • 国内域名:提供国内访问网页应用入口

Vercel 配置

进入 ChatGPT-Next-Web Github 首页 ,找到 “Deploy” 按钮,点击”Deploy” 按钮,进入 Vercel 托管网站,接下来进行 Vercel 的配置。

如果未登录过 Vercel ,需要使用 GitHub 账号进行登录。

成功登录 Vercel后,创建 Git 仓库:

接下来配置环境变量,包括 OpenAI 的 API Key 和网页访问密码:

阅读全文 »

在上一篇文章《Go 并发机制:Goroutine》中,我们讨论了 Go 如何使用 goroutine 实现并发。本文我们继续讨论 goroutine 如何利用 channel 来进行通信。

什么是 channel

Channel,通道,可看作是 goroutine 进行通信的管道(pipe)。跟水可以在管道中从一端流向另一端类似,数据也可以通过通道从一端发送,从另一端接收。

声明 channel

每一个通道都有一个具体的类型,即这个通道允许传输的数据类型。

1
ch T

一个类型为 T 的通道。

通道的零值为 nil,可以使用 make 来定义通道。例如:

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
var a chan int
if a == nil {
fmt.Println("channel a is nil, going to define it")
a = make(chan int)
fmt.Printf("Type of a is %T", a)
}
}

上面的程序中,首先声明了 a 通道,且a 通道的类型为 int。由于 a 通道开始的值为 nil,接下来进行通道的定义。

运行程序,输出:

阅读全文 »

Go 是当前一门热门的编程语言,其优秀的并发特性吸引了无数程序员的目光。

Go 的并发特性是一个比较大的话题,笔者计划从以下三个方面讨论:

  • Go goroutine
  • Go channel
  • Go select

本文讨论 Go 的 goroutine 并发机制。

并发与并行

在讨论 goroutine 之前,我们先来看下并发与并行的区别。

多线程程序在单核心的 cpu 上运行,称为并发;多线程程序在多核心的 cpu 上运行,称为并行。并发与并行并不相同,并发主要由切换时间片来实现“同时”运行,并行则是直接利用多核实现多线程的运行。

以生活中慢跑例子来说明并发与并行的区别。

一个人在进行慢跑,途中鞋带松了。这时,他停止跑步,系好鞋带,然后再继续跑步。这是并发的经典示例,即这个人能够处理跑步和系鞋带,可以理解为这个人可以“同时”(at onece)处理多个事情。

同样以慢跑来例子来说明并行的含义。假设一个人正在戴着 airpods 听音乐慢跑。在这种情况下,这个人同时(at the same time)进行慢跑和听音乐,这就是所谓的并行。

Go 使用 goroutine 和 channel 实现并发特性。

什么是 Goroutine

Goroutine 是一个轻量级的可独立运行的工作单元,可以看作是轻量级的线程。与线程相比,创建 goroutine 的成本很小,因此 go 应用程序通常会同时运行数千个 goroutine。

阅读全文 »

Apache Bench,即 ab 工具,是 Apache 提供的用来对 HTTP Web 服务器进行性能测试的工具。ab 命令不仅可以对传统的 Apache Web 服务器进行性能测试,也可以对其他的 Web 服务器进行性能测试,使用起来十分方便。

安装

在笔者 MacBook 上,ab 工具已安装好。如果是 CentOS 7 操作系统,可以使用以下命令进行安装:

1
yum -y install httpd-tools

测试是否安装成功:

1
ab -V

在笔者 MacBook 下输出:

1
2
3
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

使用

ab 命令使用起来十分简单,例如,向 http://127.0.0.1:8080/ 接口发送 1000 次请求,请求的并发为 10:

阅读全文 »

文章 《Raft 共识算法学习笔记 一:领导人选举》《Raft 共识算法学习笔记 二:日志复制》 分别讲述了 Raft 算法如何进行领导人选举和如何进行日志复制。

这篇文章继续讲述 Raft 算法如何处理集群成员节点变更的问题。

考虑一种场景,原来 Raft 集群中存在三个节点,现在需要增加2 个节点。那么,在这种情况下, Raft 算法如何能保证同一个任期内,只有一个领导者呢?

Raft 论文中,作者使用配置(configuration)来表示集群由哪些节点组合,即集群所有节点的信息集合。在稳定状态下,所有节点的配置都是一致的。

由于集群存在多个节点,因此,一次性原子地更新所有节点的配置是不可能的,集群在更新配置的过程中,可能会出现新旧配置的两个大多数:

阅读全文 »

文章 Raft 共识算法学习笔记 一:领导人选举 描述了 Raft 算法如何进行领导者选举,本文描述 Raft 共识算法如何进行日志复制。

复制状态机

在 Raft 集群中,每个服务器可以看成是一个复制状态机(Replicated State Machine),如下图。
复制状态机通常基于复制日志(replicated log)实现。每个服务器存储一个包含一系列指令的日志,并且按顺序执行指令。由于日志都包含相同顺序的指令,状态机会按照相同的顺序执行指令,由于状态机是确定的(deterministic),因此状态机会产生相同的结果。
保持这些日志的一致性(consistent)正是共识(consensus)算法的工作。

图:复制状态机工作过程:1. 客户端请求;2. 共识模块执行共识算法进行日志复制,将日志复制至集群内各个节点;3. 日志应用到状态机;4. 服务端返回请求结果

在 Raft 中,指令以日志形式进行复制。集群内只有领导者才能接收客户端请求,其他所有节点都接收来自领导者的复制日志,以达到所有节点日志的一致,并最终达到状态的一致。

Raft 日志

阅读全文 »

Raft 算法是现在分布式系统开发首选的共识算法。文章 《图解 Paxos 算法》 介绍了 Paxos 共识算法,绝大多数选用 Paxos 算法的系统(比如 Cubby),都是在 Raft 算法发布前开发的,当时没得选。新系统绝大多数选择了 Raft 算法,例如,Etcd,Consul,等。就像作者 Diego Ongaro 在 Raft 论文 In Search of an Understandable Consensus Algorithm 说的,Paxos 太难理解了,无论是对于学生还是系统开发者来说,因此 Diego Ongaro 提出了易于理解和实现的 Raft 算法。

本文讲述 Raft 算法如何进行领导者选举。

节点状态

在 Raft 中,节点有以下三种状态:

  • leader(领导者):接收 client (客户端)的所有请求,霸道总裁,一切以我为准。领导者平常的工作包括 3 个部分:处理写请求,管理日志复制,不断发送心跳信息通知其他节点”我是领导者,我还活者,你们现在不要发起新的选举“。Raft 保证任何时刻只有一个 leader
  • follower(跟随者):相当于普通群众,被动接收和处理来自领导者的消息。当领导者心跳超时时,就主动站出来,推荐自己当选候选人
  • candidate(候选人):用于选举出一个新的 leader。候选人向其他节点发送投票 (RequestVote,参考下文 Raft RPX 通信的描述)RPC 消息,通知其他节点来投票,如果赢得子大多数选票,就升级为领导者

节点状态转换示意图如下图所示:

阅读全文 »

Paxos 算法由 Leslie Lamport 在 1989 年提出的一个分布式共识算法,Paxos 算法较难理解,本文尝试以图形化方案解释 Paxos 算法。

本文在很大篇幅参考了韩健极客时间的课程《分布式协议与算法》,有兴趣了解韩老师其他课程的同学可以购买来学习下。

Lamport 提出的 Paxos 算法包括两个部分:

  • Basic Paxos 算法:多节点如何就某个值达成共识
  • Multi Paxos 思想:执行多个 Basic Paxos ,就一系列的值达成共识

Basic Paxos

问题

假设一个集群包含三个节点 A, B, C,提供只读 key-value 存储服务。只读 key-value 的意思是指,当一个 key 被创建时,它的值就确定下来了,且后面不能修改。

客户端 1 和客户端 2 同时试图创建一个 X 键。客户端 1 创建值为 "leehao.me"X ,客户端 2 创建值为 "www.leehao.me"X。在这种情况下,集群如何达成共识,实现各节点上 X 的值一致呢?

阅读全文 »

Spring Cloud 在最新版本 2020.0.0 开始,已去除了 Zuul 网关的使用,改用 Spring Cloud Gateway 作为网关。

Spring Cloud Gateway 基于 Spring WebFlux 框架实现,相对于 Zuul 来说,性能更高。

本文讲述如何在 Spring Cloud 中使用 Nacos 作为注册中心,通过 Spring Cloud Gateway 实现 API 路由的功能。

启动 Nacos

由于需要使用 Nacos 作为注册中心,网关和微服务都注册到 Nacos,因此,需要先启动一个单机版本的 Nacos。

可以参考 Nacos 官方文档 https://nacos.io/zh-cn/docs/quick-start.html 启动一个单机版本的 Nacos。启动成功后,可以通过地址 http://localhost:8868/nacos 访问,用户名 nacos,密码 nacos

启动 Gateway

在 Spring Cloud 项目 springcloudstudy 基础上创建一个 Spring Boot 子项目(有关如何在 IntelliJ Idea 创建 Spring Boot 子项目,可参考 Spring Cloud 使用 Nacos 作配置中心),添加pom.xml 依赖:

1
2
3
4
5
6
7
8
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
  • spring-cloud-starter-alibaba-nacos-discovery:使用 Nacos 作为注册中心,需要连接上 Nacos
  • spring-cloud-starter-gateway:使用 Spring Cloud Gateway 作为网关
阅读全文 »

最近公司某项目计划对数据库进行水平分库处理,因此需要实现程序根据参数自动切换数据库的功能。

本文讲述如何在 Spring Cloud + MyBatis + Druid + Oracle 环境下实现动态数据源切换的功能。

配置数据源

在两个 Oracle 数据库创建 Person 表,并插入几行数据:

1
2
3
4
5
6
7
8
9
create table Person
(
id NUMBER(8) not null,
name VARCHAR2(64) not null
)

INSERT INTO Person (id, name) VALUES (1, 'Leo');
INSERT INTO Person (id, name) VALUES (2, 'Lee');
INSERT INTO Person (id, name) VALUES (3, 'Lih');

为便于标识不同数据库的数据,可以将第三行 insert 语句改为:

1
INSERT INTO Person (id, name) VALUES (3, 'LeoLee');

创建一个 Spring Boot 项目,其 application.yml 文件添加两个 Oracle 库的连接信息:

阅读全文 »
0%