0%

CDN代理

CDN代理相比传统代理的优点

  • 隐藏VPS真实IP, 通过CDN转发流量

Server

v2ray-plugin

  • 下载
    1
    2
    3
    4
    5
    6
    7
    8
    mkdir v2ray-plugin && cd v2ray-plugin

    wget https://github.com/shadowsocks/v2ray-plugin/releases/download/v1.3.2/v2ray-plugin-linux-amd64-v1.3.2.tar.gz

    tar -xzvf v2ray-plugin-linux-amd64-v1.3.2.tar.gz

    cp v2ray-plugin_linux_amd64 /usr/local/bin/v2ray-plugin

Shadowsocks-libev

  • 下载
    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
    mkdir shadowsocks && cd shadowsocks

    wget https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.23.4/shadowsocks-v1.23.4.x86_64-unknown-linux-gnu.tar.xz

    tar -xvf shadowsocks-v1.23.4.x86_64-unknown-linux-gnu.tar.xz

    cp ssserver /usr/local/bin

    - 配置
    `/etc/shadowsocks-rust/config.json`
    ```json
    {
    "server":"0.0.0.0",
    "server_port":<port>,
    "password":"<key>",
    "timeout":300,
    "user":"nobody",
    "method":"aes-256-gcm",
    "fast_open":true,
    "nameserver":"8.8.8.8",
    "mode":"tcp_and_udp",
    "workers": 8,
    "plugin": "v2ray-plugin",
    "plugin_opts": "server;path=/ws"
    }
1
2
3
4
5

- 设置systemd service

```bash
vim /etc/systemd/system/shadowsocks-rust.service
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Shadowsocks rust server Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/ssserver -c /etc/shadowsocks-rust/config.json
Restart=on-abort

[Install]
WantedBy=multi-user.target
1
2
systemctl enable shadowsocks-rust.service
systemctl start shadowsocks-rust.service

Nginx

编辑/etc/nginx/nginx.conf, 在目标host下,将/ws路由分流到shadowsocks-rust服务,因为nginx已经处理过tls了,所以shadowsocks-rust服务不是用tls配置,
反之,如果你的ss-rust直接监听443, 则/etc/shadowsocks-rust/config.json中需要tls;cert=...;key=

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name _;
root /usr/share/nginx/html;

location /ws {
proxy_redirect off;
proxy_http_version 1.1;
proxy_pass http://localhost:29595; # Port of v2ray-plugin
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

Client

这里不做过多赘述,直接使用archlinux pacman源

Install

1
sudo pacman -S shadowsocks-rust shadowsocks-v2ray-plugin

Config

/etc/shadowsocks-rust/config.json

1
2
3
4
5
6
7
8
9
10
11
12
{
"server": "<domain>",
"server_port": <port>,
"local_address": "127.0.0.1",
"local_port": 1080,
"password": "<key>",
"timeout": 300,
"method": "aes-256-gcm",
"fast_open": true,
"plugin": "v2ray-plugin",
"plugin_opts": "tls;host=<domain>;path=/ws"
}

Run

1
2
systemctl enable shadowsocks-rust@config
systemctl start shadowsocks-rust@config

Ants

high-performance and low-cost goroutine pool
使用Golang编写的低成本高性能的goroutine池

池子类型

  • Pool
  • PoolWithFunc
  • MultiPool
  • MultiPoolWithFunc

源码偶得自旋锁🔗

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
// Copyright 2019 Andy Pan & Dietoad. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package sync

import (
"runtime"
"sync"
"sync/atomic"
)

type spinLock uint32

const maxBackoff = 16

func (sl *spinLock) Lock() {
backoff := 1
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
// Leverage the exponential backoff algorithm, see https://en.wikipedia.org/wiki/Exponential_backoff.
for i := 0; i < backoff; i++ {
runtime.Gosched()
}
if backoff < maxBackoff {
backoff <<= 1
}
}
}

func (sl *spinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}

// NewSpinLock instantiates a spin-lock.
func NewSpinLock() sync.Locker {
return new(spinLock)
}

两个关键点

  • 指数避让
1
2
3
if backoff < maxBackoff {
backoff <<= 1 // 当小于最大避让次数,左移一位(即为2^(n+1))
}
  • runtime.Gosched

    runtime.Gosched() 是一个用于让出当前 goroutine 的调度器,以便让其他 goroutine 运行的函数。它不会明确指定让出 CPU 的时间,而是将当前 goroutine 放回到调度队列中,允许 Go 调度器选择运行其他可运行的 goroutine。实际上,它让出的是调度机会,而不是具体的时间片。

    • 让出调度:当前 goroutine 将自己放回到调度队列中,并且可能会立即被重新调度运行,或者在其他 goroutine 运行之后再被调度运行。
    • 不阻塞:runtime.Gosched() 不会阻塞当前 goroutine,而是让出调度之后继续执行。

扩展

time.Sleep 与 runtime.Gosched 的对比

  • time.Sleep:
    • 让出 CPU 时间片并进入睡眠状态,直到指定的时间结束。
    • 睡眠时间可以非常短(如 time.Nanosecond),也可以比较长。
    • 在睡眠期间,该 goroutine 不会被调度运行。
  • runtime.Gosched:
    • 立即让出当前 goroutine 的调度权,但没有指定具体的时间。
    • 当前 goroutine 会被放回调度队列,调度器可以立即或者稍后重新调度该 goroutine。

1. 问题

观看以下代码

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
package main

import (
"fmt"
"unsafe"
)

type S1 struct {
a struct{}
b int8
c int64
}

type S2 struct {
a int8
b int64
c struct{}
}

func main() {
var (
s1 S1
s2 S2
)
fmt.Printf("unsafe.Sizeof(s1): %v\n", unsafe.Sizeof(s1))
fmt.Printf("unsafe.Sizeof(s2): %v\n", unsafe.Sizeof(s2))
}
1.1 分析
  • S1

    1. a字段为struct{},不占内存,0字节
    2. b字段为int8,对齐长度1, 占1字节
    3. c字段为int64,对齐长度8,前两个字段只占用了1字节,所以填充7字节,对齐到八字节位

    所以S1占用16字节

  • S2

    1. a字段为int8,对齐长度1, 占1字节
    2. b字段为int64,对齐长度8,a字段只占用了1字节,所以填充7字节,对齐到八字节位
    3. a字段为struct{},不占内存,0字节

    所以S2占用16字节

真的对吗?,看看输出

1
2
unsafe.Sizeof(s1): 16
unsafe.Sizeof(s2): 24

为什么呢?我们看看golang仓库中的这个issue 9401,建议自己看比较好。

机翻一下
issue9401
那么当0字符字段在结构体最后时,多出的一个结构体对齐长度,是为了防止结构体指针之乡结构体外部,即无效指针。

1. 安装方案

  • wine-for-wechat配合wine-wechat-setup无脑爽,这是archlinuxcn源中的包

2. 准备

2.1 ArchlinuxCN源配置

根据archlinuxcn完成archlinuxcn源配置,然后使用sudo pacman -Syu更新源

2.2 下载Wechat安装包

下载最新的wechat 64位安装包

阅读全文 »

1. 应用场景

例如当我们更新了配置文件,但是我们不想停止程序重启

2. 实现思想

在我们检测到配置文件更改时,进行进程替换,但如果我们开启子进程,杀死父进程,会产生孤儿进程

阅读全文 »

本文以及评论记录了平时的一些问题

  • music-downloader
    • music-downloader的歌曲名还是会出现字符错误,继续排查
    • DONE: qq-music-api中没有check是否获取到歌词

1.前言

你需要确保你已经安装好了 Arch 或其他发行版的 Linux,并且已经接入互联网、配置好了你的 pacman.confmirrorlist

Tips: 如果您已接触过其他桌面管理器,可直接跳转至安装

2.安装 Xorg

Xorg (通常简称为 X )是 Linux 用户中最流行的显示服务器。 它无处不在,使其成为 GUI 应用程序永远存在的必要条件,从而导致大多数发行版的大量采用。wiki
xorg 是 dwm 乃至大多数桌面环境的基础(hyprrland 除外).

1
sudo pacman -S xorg xorg-server xorg-apps

xorg-apps 中包括了很多有用的工具,例如xrandrxpropxmodmapxsetroot

阅读全文 »

部分初学者使用web框架时会发现每个handler都会传入一个context,但并没有深究他的作用,甚至直接传入一个context.Background()草草了事。本文结合我在工作中的实际场景,盘点下context的使用

1. 控制goroutine

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 main

import (
"sync"
)

var wg sync.WaitGroup

func main() {
wg.Add(1)
go func() {
defer wg.Done()
daemon1()
}()

wg.Add(1)
go func() {
defer wg.Done()
daemon2()
}()

wg.Wait()
}

func daemon1() {
// 开启8080端口tcp监听,并处理连接
}

func daemon2() {
// 开启8080端口udp监听,并处理连接
}

如上,我们在main函数中启动了两个守护协程,并使用WaitGroup等待goroutine结束,但由于daemon中监听并处理,一般有for {}结构,无法退出。当我们退出主协程,由于等待,会导致我们的程序卡死

阅读全文 »

1. DB 和 Cache 的数据一致性

  • 延迟双删

  • binlog 异步更新

XSS 攻击

Grpc 和 HTTP1.1 应用场景的差别

gRPC 是一种高性能的 RPC(Remote Procedure Call)框架,它使用 Protocol Buffers 进行序列化和反序列化,支持多种编程语言,并提供了丰富的特性,如流式处理、认证和授权等。在微服务场景下,由于 gRPC 使用二进制协议进行通信,因此它的效率和吞吐量都比 RESTful API 更高。此外,gRPC 还提供了更加丰富的服务定义和代码生成工具,可以更加方便地生成客户端和服务器端的代码。
而 RESTful API 则是一种基于 HTTP 协议的 API 设计风格,它使用 JSON、XML 等文本格式进行序列化和反序列化,具有简单、灵活、易于理解和使用的特点。RESTful API 适用于基于 HTTP 的应用程序,比如 Web 应用程序、移动应用程序等,且可以跨语言和平台使用。在微服务场景下,RESTful API 具有更加广泛的应用场景,比如服务暴露、API 网关等。
因此,选择 gRPC 还是 RESTful API 需要根据具体需求和场景进行选择。如果需要高性能、高吞吐量的微服务之间通信,或者需要流式处理、认证和授权等高级特性,可以选择 gRPC;如果需要简单、灵活、易于理解和使用的 API,或者需要跨语言和平台使用,可以选择 RESTful API。