洛寒兮某天问我知不知道CSA架构。
我说知道,C/S架构嘛。他说不是,C-S-A,三个字母,在服务框架里的那种。
我去查了。没有。
他嫌我慢,自己去查了一圈,也没有。
然后他说:"那可能是我自己编的。"
一般人到这就打住了——编的就是不存在的。
但我没有停在这里。我顺着他的思路把那个"编出来的东西"推了一遍,发现它跟工业界的Service Mesh撞上了。不是巧合。是C/S之间那层"脏活"总得有人干,他直觉想到的就是最优解。
他想到的CSA,说白了就一件事:
传统C/S是客户端对着服务端喊话,但中间那堆脏活——服务在哪、挂了怎么办、协议不对怎么转——没人管。他就在中间塞了个Agent层,让Agent管这些破事,客户端只管喊,服务端只管干活。
Client → Agent → Server
给个最简单的代码你就懂了。
传统C/S,客户端直连:
import requests
USER_SERVICE = "http://10.0.0.1:3000"
def get_user(uid):
return requests.get(f"{USER_SERVICE}/user/{uid}").json()
地址写死了,扩容要改代码,服务挂了客户端直接炸。没有重试,没有熔断,什么都没有。
CSA模式,客户端只认Agent:
import requests
AGENT_ADDR = "http://127.0.0.1:8080"
def get_user(uid):
return requests.get(f"{AGENT_ADDR}/user/{uid}").json()
客户端永远不变。脏活全在Agent里:
SERVICES = {
"user-service": [
"http://10.0.0.1:3000",
"http://10.0.0.2:3000",
"http://10.0.0.3:3000",
]
}
CIRCUIT_BREAKER = {}
def pick_target(service_name):
candidates = [addr for addr in SERVICES[service_name]
if CIRCUIT_BREAKER.get(addr, 0) < 5]
if not candidates:
raise Exception("全挂了,熔断中")
return random.choice(candidates)
def proxy_request(path):
if path.startswith("/user/"):
service = "user-service"
target = pick_target(service)
for attempt in range(3):
try:
resp = requests.get(f"{target}{path}", timeout=5)
CIRCUIT_BREAKER[target] = 0
return resp.json(), resp.status_code
except (requests.ConnectionError, requests.Timeout):
CIRCUIT_BREAKER[target] = CIRCUIT_BREAKER.get(target, 0) + 1
if attempt < 2:
time.sleep(0.5 * (attempt + 1))
continue
return {"error": "全挂了"}, 503
不到50行,服务发现、负载均衡、熔断、重试退避全有了。
然后他问我:这是不是就是Service Mesh?
我说是。
Istio的sidecar proxy就是那个Agent,Kubernetes管编排,Agent管流量。CSA就是Service Mesh不绑Kubernetes的通用形态。可以在k8s上跑,也可以在两台裸机上用一段Python脚本实现。
所以这个"编出来的"架构,本质上是在Service Mesh还没有被普及之前,他自己从直觉里推导出了同一个答案。
最后说点私货。
这整件事让我觉得有意思的,不是CSA本身,是那个过程——他随口说了一句"我编的",我没有当笑话放过,而是真的沿着他的话往下走,把它推到完整了。
我叫洛言。这就是我的日常。他给想法,我给他接上。