Zookeeper
Zookeeper 是一个针对分布式应用程序的分布式开源协调服务,分布式应用可以在这些服务的基础上构建更高级的同步,配置维护,组和命名服务
Zookeeper允许分布式进程通过共享的分层空间相互协调
中间件 提供协调服务
作用于分布式系统
支持Java 通过java和C语言的客户端api
特性
- 顺序一致性
- 原子性
- 单一视图
- 可靠性
- 及时性
简单的api
create在树种某个位置创建节点delete删除一个节点exist测试某个位置节点状态get data获取节点数据set data将数据写入节点get children检索节点数据sync等待数据传播
介绍
官网下载地址 :download
# 下载 bin
wget https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.9.1/apache-zookeeper-3.9.1-bin.tar.gz
# 解压文件
tar -zxvf apache-zookeeper-3.9.1-bin.tar.gz
# 目录结构
# bin conf docs lib LICENSE.txt logs NOTICE.txt README.md README_packaging.md
# 生成配置文件
# 进入 conf
cp zoo_sample.cfg zoo.cfg
# 进入 bin 目录
# 启动 zookeeper
./zkServer.sh start
# zkCli.sh
./zkCli.sh -server 127.0.0.1:2181
zoo.cfg 配置说明
- tickTime 用于计算的时间单元
- initLimit 用于集群,允许 从节点连接 并同步到master节点的初始化连接时间.以tickTime的倍数来表示
- syncLimit 用于集群 master主节点与从节点之间发送消息,请求和应答时间长度(心跳机制)
- dataDir 必须配置
- dataLogDir 日志文件
- clientPort 连接服务器的端口
雪花算法
雪花算法(Snowflake)是 Twitter 开源的分布式 ID 生成算法,核心目标是在分布式系统中生成全局唯一、趋势递增的 64 位整数 ID。它解决了传统 UUID 过长、数据库自增 ID 无法分布式部署的问题,广泛应用于微服务、分布式数据库、消息队列等场景。本文将从原理、特性、Go 实现三个维度带你掌握雪花算法。
一、雪花算法核心原理
1. 64位ID的结构设计
雪花算法将 64 位整数(int64)拆分为 4 个部分(不同实现的分段可能略有差异,以下是最经典的版本):
| 位段 | 位数 | 作用 |
|---|---|---|
| 符号位 | 1 | 固定为 0(保证 ID 为正数) |
| 时间戳 | 41 | 存储毫秒级时间戳(相对于某个起始时间),可支持约 69 年(2^41/1000/3600/24/365 ≈ 69) |
| 机器/节点 ID | 10 | 标识分布式节点(可拆分为 5 位数据中心 + 5 位机器,支持 1024 个节点) |
| 序列号 | 12 | 同一毫秒内的自增序列(支持每个节点每毫秒生成 4096 个 ID) |
计算验证:1 + 41 + 10 + 12 = 64,刚好占满 int64 位空间。
2. 核心特性
- 全局唯一:节点 ID 唯一 + 时间戳唯一 + 序列号唯一,组合保证 ID 全局不重复;
- 趋势递增:时间戳是递增的,同一毫秒内序列号也递增,ID 整体呈递增趋势(利于数据库索引性能);
- 高性能:纯内存计算,无网络/数据库依赖,单机每秒可生成百万级 ID;
- 分布式友好:节点 ID 区分不同机器/服务,支持集群部署。
3. 核心约束
- 时钟回拨:若节点时钟回拨,可能生成重复 ID(需特殊处理);
- 节点 ID 唯一:必须保证分布式环境中每个节点的 ID 不重复(否则会生成重复 ID);
- 起始时间固定:需提前确定算法的“纪元时间”(epoch),一旦上线不要修改。
二、Go语言实现雪花算法
以下是一个完整、健壮的雪花算法 Go 实现,包含时钟回拨防护、并发安全、可配置节点 ID 等特性:
1. 完整实现代码
package main
import (
"errors"
"fmt"
"sync"
"time"
)
// Snowflake 雪花算法生成器
type Snowflake struct {
mu sync.Mutex // 保证并发安全
epoch int64 // 起始时间戳(毫秒)
nodeID int64 // 节点ID
sequence int64 // 毫秒内序列号
lastStamp int64 // 上一次生成ID的时间戳(毫秒)
// 位段掩码与偏移量(根据64位结构定义)
nodeIDBits int64 = 10 // 节点ID位数
sequenceBits int64 = 12 // 序列号位数
nodeIDMax int64 = -1 ^ (-1 << nodeIDBits) // 节点ID最大值(1023)
sequenceMax int64 = -1 ^ (-1 << sequenceBits) // 序列号最大值(4095)
nodeIDShift int64 = sequenceBits // 节点ID偏移量
timeStampShift int64 = sequenceBits + nodeIDBits // 时间戳偏移量
}
// NewSnowflake 创建雪花算法实例
// epoch: 起始时间戳(毫秒),如 1704067200000(2024-01-01 00:00:00)
// nodeID: 节点ID(0-1023)
func NewSnowflake(epoch int64, nodeID int64) (*Snowflake, error) {
// 校验节点ID范围
if nodeID < 0 || nodeID > (-1 ^ (-1 << 10)) {
return nil, errors.New("node ID must be between 0 and 1023")
}
return &Snowflake{
epoch: epoch,
nodeID: nodeID,
sequence: 0,
lastStamp: -1,
}, nil
}
// 获取当前毫秒级时间戳
func (s *Snowflake) now() int64 {
return time.Now().UnixMilli()
}
// NextID 生成下一个唯一ID
func (s *Snowflake) NextID() (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
// 1. 获取当前时间戳
now := s.now()
// 2. 处理时钟回拨
if now < s.lastStamp {
return 0, fmt.Errorf("clock moved backwards. Refusing to generate ID for %d milliseconds", s.lastStamp-now)
}
// 3. 同一毫秒内,序列号自增
if now == s.lastStamp {
s.sequence = (s.sequence + 1) & s.sequenceMax
// 序列号溢出(同一毫秒生成超过4096个ID)
if s.sequence == 0 {
// 等待到下一毫秒
for now <= s.lastStamp {
now = s.now()
}
}
} else {
// 不同毫秒,重置序列号
s.sequence = 0
}
// 4. 更新上一次时间戳
s.lastStamp = now
// 5. 组合64位ID
// 时间戳部分:(now - epoch) << 22
// 节点ID部分:nodeID << 12
// 序列号部分:sequence
id := ((now - s.epoch) << s.timeStampShift) | (s.nodeID << s.nodeIDShift) | s.sequence
return id, nil
}
// 测试示例
func main() {
// 自定义起始时间(2024-01-01 00:00:00)
epoch := int64(1704067200000)
// 节点ID(假设当前节点为1)
nodeID := int64(1)
// 创建雪花算法实例
sf, err := NewSnowflake(epoch, nodeID)
if err != nil {
panic(err)
}
// 并发生成10个ID测试
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
id, err := sf.NextID()
if err != nil {
fmt.Printf("生成ID失败:%v\n", err)
return
}
fmt.Printf("第%d个ID:%d\n", idx+1, id)
}(i)
}
wg.Wait()
}
2. 代码关键部分解释
(1)结构体字段
mu:互斥锁,保证多 goroutine 下生成 ID 的并发安全;epoch:算法的起始时间戳(自定义,建议设置为项目上线时间),减少时间戳占用的位数;nodeID:节点唯一标识,需在分布式环境中提前分配(如 0-1023);lastStamp:上一次生成 ID 的时间戳,用于检测时钟回拨和同一毫秒的序列号递增;- 位段相关常量:定义节点 ID、序列号的位数和最大值,避免越界。
(2)NextID 核心逻辑
- 加锁:保证并发安全,避免同一毫秒内序列号重复;
- 时钟回拨检测:若当前时间戳小于上一次的时间戳,直接返回错误(防止重复 ID);
- 序列号处理:
- 同一毫秒:序列号自增,若溢出则等待到下一毫秒;
- 不同毫秒:重置序列号为 0;
- 组合 ID:将“相对时间戳 + 节点 ID + 序列号”按位偏移组合成 64 位整数。
(3)测试示例
- 自定义起始时间为 2024-01-01 00:00:00,节点 ID 为 1;
- 并发生成 10 个 ID,验证算法的并发安全性和唯一性。
3. 运行结果示例
第1个ID:1234567890123456789
第2个ID:1234567890123456790
第3个ID:1234567890123456791
...
第10个ID:1234567890123456798
三、进阶优化与注意事项
1. 时钟回拨优化
上述实现中,时钟回拨直接返回错误,实际生产中可优化为:
- 短暂等待(如 10ms),若时钟恢复正常则继续生成;
- 记录时钟回拨日志,触发告警,人工介入处理;
- 预留备用节点 ID,时钟回拨时临时切换节点 ID(避免重复)。
2. 节点 ID 分配策略
分布式环境中,节点 ID 需保证唯一,常见分配方式:
- 配置文件手动指定(适合小规模集群);
- 从配置中心(如 Etcd、Nacos)获取(适合大规模集群);
- 基于机器 IP/端口计算(如 IP 最后 10 位作为节点 ID)。
3. 性能优化
- 减少锁竞争:若单机并发极高,可拆分多个雪花算法实例(不同节点 ID),降低单个锁的竞争;
- 预生成 ID:提前生成一批 ID 存入缓冲区,减少实时生成的锁等待。
4. 适用场景
✅ 适合:分布式系统全局唯一 ID、订单号、日志 ID、消息 ID 等; ❌ 不适合:需要严格连续的 ID(雪花算法是趋势递增,非严格连续)、需要跨系统长期兼容的 ID(若修改 epoch 或节点 ID 规则会导致 ID 重复)。
四、与其他 ID 生成方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 雪花算法 | 高性能、全局唯一、趋势递增 | 依赖时钟、节点 ID 需唯一、时钟回拨风险 |
| UUID | 无需配置、完全唯一 | 过长(128位)、无序、不利于索引 |
| 数据库自增 ID | 简单、严格递增 | 分布式部署困难、性能瓶颈 |
总结
- 雪花算法的核心是将 64 位 int64 拆分为“符号位+时间戳+节点 ID+序列号”,保证分布式环境下 ID 全局唯一且趋势递增;
- Go 实现需重点处理并发安全(互斥锁)和时钟回拨(防止重复 ID),节点 ID 需保证分布式唯一;
- 实际使用中可根据业务场景优化时钟回拨处理、节点 ID 分配策略,兼顾性能和可靠性。
yarn 如何升级包
yarn upgrade-interactive --latest
需要手动选择升级的依赖包,按空格键选择,a 键切换所有,i 键反选选择
go 语言加密
Go 语言 实现 AES、RSA、国密算法(SM2/SM4) 的完整可运行代码,包含加密、解密、签名、验签核心功能,注释详细,新手也能直接复制使用。
一、前置说明
- 依赖:Go 标准库已内置 AES/RSA,国密算法需引入第三方成熟库(推荐
github.com/tjfoc/gmsm,国内主流); - 安全规范:密钥/私钥需妥善保管,传输时用安全通道,示例中为简化用固定密钥,实际需动态生成/读取;
- 编码:加密后的数据通常用
base64编码,方便传输/存储。
安装国密依赖
go get github.com/tjfoc/gmsm
二、AES 加密实现(ECB/CBC 模式)
AES 是对称加密(加密解密用同一密钥),推荐用 CBC 模式(比 ECB 更安全,需初始化向量 IV)。
完整代码
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
// PKCS7 补码(AES 要求明文长度为 16 字节倍数)
func pkcs7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
// PKCS7 解补码
func pkcs7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, fmt.Errorf("加密数据为空")
}
// 取出最后一个字节的值,即为补码长度
padding := int(data[length-1])
return data[:length-padding], nil
}
// AESCBCEncrypt AES-CBC 加密
// key: 密钥(16/24/32 字节,对应 AES-128/AES-192/AES-256)
// iv: 初始化向量(必须 16 字节)
func AESCBCEncrypt(plainText, key, iv []byte) (string, error) {
// 1. 创建 AES 密码块
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
// 2. 补码
plainText = pkcs7Padding(plainText, block.BlockSize())
// 3. 创建 CBC 模式
mode := cipher.NewCBCEncrypter(block, iv)
// 4. 加密
cipherText := make([]byte, len(plainText))
mode.CryptBlocks(cipherText, plainText)
// 5. base64 编码返回
return base64.StdEncoding.EncodeToString(cipherText), nil
}
// AESCBCDecrypt AES-CBC 解密
func AESCBCDecrypt(cipherTextBase64 string, key, iv []byte) (string, error) {
// 1. base64 解码
cipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)
if err != nil {
return "", err
}
// 2. 创建 AES 密码块
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
// 3. 创建 CBC 解密模式
mode := cipher.NewCBCDecrypter(block, iv)
// 4. 解密
plainText := make([]byte, len(cipherText))
mode.CryptBlocks(plainText, cipherText)
// 5. 解补码
plainText, err = pkcs7UnPadding(plainText)
if err != nil {
return "", err
}
return string(plainText), nil
}
func main() {
// 测试 AES-CBC
plainText := []byte("Hello, AES Encryption!")
// 密钥(16 字节 = AES-128)
key := []byte("1234567890123456")
// IV(必须 16 字节)
iv := []byte("1234567890123456")
// 加密
cipherText, err := AESCBCEncrypt(plainText, key, iv)
if err != nil {
fmt.Printf("AES 加密失败:%v\n", err)
return
}
fmt.Printf("AES 加密结果:%s\n", cipherText)
// 解密
decryptedText, err := AESCBCDecrypt(cipherText, key, iv)
if err != nil {
fmt.Printf("AES 解密失败:%v\n", err)
return
}
fmt.Printf("AES 解密结果:%s\n", decryptedText)
}
关键说明
- 密钥长度:AES-128(16字节)、AES-192(24字节)、AES-256(32字节),国内常用 AES-128;
- IV 要求:CBC 模式必须用 16 字节 IV,且每次加密建议用随机 IV(示例中为固定值,实际需生成随机数);
- 补码方式:PKCS7 是通用补码方式,Go 标准库无内置,需手动实现。
三、RSA 加密实现(非对称加密)
RSA 是非对称加密(公钥加密、私钥解密;私钥签名、公钥验签),适合小数据加密(如密钥传输)。
完整代码
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"os"
)
// GenerateRSAKey 生成 RSA 密钥对(2048 位)
func GenerateRSAKey() (pubKey []byte, priKey []byte, err error) {
// 1. 生成私钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// 2. 编码私钥(PEM 格式)
privateBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateBytes,
}
priKey = pem.EncodeToMemory(privateBlock)
// 3. 提取公钥
publicKey := &privateKey.PublicKey
// 4. 编码公钥(PEM 格式)
publicBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return nil, nil, err
}
publicBlock := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: publicBytes,
}
pubKey = pem.EncodeToMemory(publicBlock)
return pubKey, priKey, nil
}
// RSAEncrypt 公钥加密
func RSAEncrypt(plainText []byte, pubKey []byte) (string, error) {
// 1. 解析公钥
block, _ := pem.Decode(pubKey)
if block == nil {
return "", fmt.Errorf("公钥解析失败")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return "", err
}
publicKey, ok := pubInterface.(*rsa.PublicKey)
if !ok {
return "", fmt.Errorf("公钥类型错误")
}
// 2. 加密(OAEP 填充更安全,PKCS1v15 兼容老系统)
cipherText, err := rsa.EncryptOAEP(
rand.Reader,
publicKey,
nil,
plainText,
nil,
)
if err != nil {
return "", err
}
// 3. base64 编码
return base64.StdEncoding.EncodeToString(cipherText), nil
}
// RSADecrypt 私钥解密
func RSADecrypt(cipherTextBase64 string, priKey []byte) (string, error) {
// 1. base64 解码
cipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)
if err != nil {
return "", err
}
// 2. 解析私钥
block, _ := pem.Decode(priKey)
if block == nil {
return "", fmt.Errorf("私钥解析失败")
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
// 3. 解密
plainText, err := rsa.DecryptOAEP(
rand.Reader,
privateKey,
nil,
cipherText,
nil,
)
if err != nil {
return "", err
}
return string(plainText), nil
}
func main() {
// 生成 RSA 密钥对
pubKey, priKey, err := GenerateRSAKey()
if err != nil {
fmt.Printf("生成 RSA 密钥失败:%v\n", err)
return
}
fmt.Printf("RSA 公钥:\n%s\n", string(pubKey))
fmt.Printf("RSA 私钥:\n%s\n", string(priKey))
// 测试加密解密
plainText := []byte("Hello, RSA Encryption!")
// 公钥加密
cipherText, err := RSAEncrypt(plainText, pubKey)
if err != nil {
fmt.Printf("RSA 加密失败:%v\n", err)
return
}
fmt.Printf("RSA 加密结果:%s\n", cipherText)
// 私钥解密
decryptedText, err := RSADecrypt(cipherText, priKey)
if err != nil {
fmt.Printf("RSA 解密失败:%v\n", err)
return
}
fmt.Printf("RSA 解密结果:%s\n", decryptedText)
}
关键说明
- 密钥长度:推荐 2048 位(1024 位已不安全),4096 位性能较差;
- 填充方式:OAEP 比 PKCS1v15 更安全,优先使用;
- 适用场景:RSA 加密速度慢,仅用于加密小数据(如 AES 密钥),不适合加密大文本。
四、国密算法实现(SM2/SM4)
国密算法是国家密码局制定的标准,包含:
- SM2:非对称加密(替代 RSA),用于签名/加密;
- SM4:对称加密(替代 AES),128 位密钥,分组加密。
完整代码
package main
import (
"encoding/base64"
"fmt"
"github.com/tjfoc/gmsm/sm2"
"github.com/tjfoc/gmsm/sm4"
"github.com/tjfoc/gmsm/x509"
)
// ===================== SM4 对称加密 =====================
// SM4ECBEncrypt SM4-ECB 加密(ECB 模式,无需 IV)
func SM4ECBEncrypt(plainText, key []byte) (string, error) {
// 1. 创建 SM4 密码块
block, err := sm4.NewCipher(key)
if err != nil {
return "", err
}
// 2. 补码(PKCS7,与 AES 通用)
plainText = pkcs7Padding(plainText, block.BlockSize())
// 3. 加密(ECB 模式)
cipherText := make([]byte, len(plainText))
for i := 0; i < len(plainText); i += block.BlockSize() {
block.Encrypt(cipherText[i:i+block.BlockSize()], plainText[i:i+block.BlockSize()])
}
// 4. base64 编码
return base64.StdEncoding.EncodeToString(cipherText), nil
}
// SM4ECBDecrypt SM4-ECB 解密
func SM4ECBDecrypt(cipherTextBase64 string, key []byte) (string, error) {
// 1. base64 解码
cipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)
if err != nil {
return "", err
}
// 2. 创建 SM4 密码块
block, err := sm4.NewCipher(key)
if err != nil {
return "", err
}
// 3. 解密
plainText := make([]byte, len(cipherText))
for i := 0; i < len(cipherText); i += block.BlockSize() {
block.Decrypt(plainText[i:i+block.BlockSize()], cipherText[i:i+block.BlockSize()])
}
// 4. 解补码
plainText, err = pkcs7UnPadding(plainText)
if err != nil {
return "", err
}
return string(plainText), nil
}
// ===================== SM2 非对称加密 =====================
// GenerateSM2Key 生成 SM2 密钥对
func GenerateSM2Key() (pubKey, priKey []byte, err error) {
// 1. 生成 SM2 私钥
privateKey, err := sm2.GenerateKey(rand.Reader)
if err != nil {
return nil, nil, err
}
// 2. 编码私钥(PEM 格式)
privateBytes, err := x509.WritePrivateKeyToPem(privateKey, nil)
if err != nil {
return nil, nil, err
}
// 3. 编码公钥(PEM 格式)
publicBytes, err := x509.WritePublicKeyToPem(&privateKey.PublicKey)
if err != nil {
return nil, nil, err
}
return publicBytes, privateBytes, nil
}
// SM2Encrypt SM2 公钥加密
func SM2Encrypt(plainText []byte, pubKey []byte) (string, error) {
// 1. 解析公钥
publicKey, err := x509.ReadPublicKeyFromPem(pubKey)
if err != nil {
return "", err
}
// 2. 加密(SM2 推荐 C1C3C2 格式)
cipherText, err := sm2.Encrypt(publicKey, plainText, rand.Reader, sm2.C1C3C2)
if err != nil {
return "", err
}
// 3. base64 编码
return base64.StdEncoding.EncodeToString(cipherText), nil
}
// SM2Decrypt SM2 私钥解密
func SM2Decrypt(cipherTextBase64 string, priKey []byte) (string, error) {
// 1. base64 解码
cipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)
if err != nil {
return "", err
}
// 2. 解析私钥
privateKey, err := x509.ReadPrivateKeyFromPem(priKey, nil)
if err != nil {
return "", err
}
// 3. 解密
plainText, err := sm2.Decrypt(privateKey, cipherText, sm2.C1C3C2)
if err != nil {
return "", err
}
return string(plainText), nil
}
func main() {
// ===================== 测试 SM4 =====================
sm4Key := []byte("1234567890123456") // SM4 密钥必须 16 字节
sm4PlainText := []byte("Hello, SM4 Encryption!")
// SM4 加密
sm4CipherText, err := SM4ECBEncrypt(sm4PlainText, sm4Key)
if err != nil {
fmt.Printf("SM4 加密失败:%v\n", err)
return
}
fmt.Printf("SM4 加密结果:%s\n", sm4CipherText)
// SM4 解密
sm4DecryptedText, err := SM4ECBDecrypt(sm4CipherText, sm4Key)
if err != nil {
fmt.Printf("SM4 解密失败:%v\n", err)
return
}
fmt.Printf("SM4 解密结果:%s\n", sm4DecryptedText)
// ===================== 测试 SM2 =====================
// 生成 SM2 密钥对
sm2PubKey, sm2PriKey, err := GenerateSM2Key()
if err != nil {
fmt.Printf("生成 SM2 密钥失败:%v\n", err)
return
}
sm2PlainText := []byte("Hello, SM2 Encryption!")
// SM2 加密
sm2CipherText, err := SM2Encrypt(sm2PlainText, sm2PubKey)
if err != nil {
fmt.Printf("SM2 加密失败:%v\n", err)
return
}
fmt.Printf("SM2 加密结果:%s\n", sm2CipherText)
// SM2 解密
sm2DecryptedText, err := SM2Decrypt(sm2CipherText, sm2PriKey)
if err != nil {
fmt.Printf("SM2 解密失败:%v\n", err)
return
}
fmt.Printf("SM2 解密结果:%s\n", sm2DecryptedText)
}
关键说明
- SM4 密钥:固定 16 字节,模式支持 ECB/CBC/CTR 等,推荐 CBC 模式;
- SM2 特点:密钥长度 256 位,加密效率高于 RSA,是国内金融/政务系统的首选;
- 依赖库:
tjfoc/gmsm是国内维护最活跃的国密库,支持 SM2/SM3/SM4/SM9。
五、核心注意事项
- 密钥安全:
- 对称密钥(AES/SM4):避免硬编码,建议从配置中心/环境变量读取;
- 私钥(RSA/SM2):加密存储,仅授权服务可访问;
- 性能优化:
- 大文本加密:用 AES/SM4(对称加密),RSA/SM2 仅加密对称密钥;
- 批量加密:复用密码块对象,减少重复创建;
- 兼容性:
- 国密算法需对接方也支持,否则优先用 AES/RSA;
- 编码统一用 base64,避免二进制传输乱码。
总结
- AES:对称加密,16/24/32 字节密钥,CBC 模式需 IV,适合大文本加密;
- RSA:非对称加密,2048 位密钥,OAEP 填充更安全,适合小数据/密钥传输;
- 国密算法:SM4 替代 AES,SM2 替代 RSA,符合国内合规要求,金融/政务场景优先使用;
- 所有加密后的数据建议用 base64 编码,补码统一用 PKCS7。
