Fork me on GitHub

<<领域驱动开发>>摘要

分层

领域层 – 核心
应用层 – 领域的一个使用场景
基础设施 – 实现的支撑系统

构件

Entity – 需要追踪生命周期的具有唯一标识的对象
Value Object – 属性对象,一般不可变
Service – 放置不属于领域层对象(Entity或Value Object)的操作
Aggregate – 领域对象的集合,以Entity作为跟外部交互的root,有且只有一个root,内部对象封装在它里面
Factory – 封装对象创建逻辑
Repository – 跟持久化交互的层,封装简单存储、恢复对象的操作

其他模式

specification 一种VO,封装条件逻辑,在验证、从集合中选择对象、根据要求创建对象的时候使用

Intention-Revealing interface 接口设计原则,只描述意图而隐藏实现。命名类和操作时要描述它们的效果和目的,而不要表露它们通过何种方式达到目的。清楚地分离函数、命令或查询,函数描述它的行为,命令需要说明它的副作用。

side-effect-free function 尽可能把程序逻辑放到函数中,因为函数不产生副作用。如果发现一个适合承担复杂逻辑职责的概念,就可以把这个复杂逻辑放到value object中。

assertion 使用断言把副作用表示出来。

closure of operation 闭合操作,实现者的类型和参数、返回值的类型一致,那么这个操作没有引入其他依赖类型,可以认为是一个闭合操作。

柔性设计

去掉类之间不必要的关联,保持低耦合。低耦合的极致是standalone class。
每多产生一个概念-显示或隐式,都会加重理解的负担。

阅读更多...

zap源码阅读

zap是Uber开源的golang日志库,以结构化日志、高性能、可扩展的特点受到许多开发者的欢迎。

使用

创建logger

zap对外提供了两个不同的日志对象,强类型的Logger和简化使用方式的SugaredLogger

  • Logger创建

    • 低级API

      func New(core zapcore.Core, options ...Option) *Logger

    • 通过配置创建
      使用了builder模式,通过Config对象的Build方法创建

      func (cfg Config) Build(opts ...Option) (*Logger, error)

      配置对象可以使用预设的NewDevelopmentConfigNewProductionConfig创建,也可以反序列化json或yaml来创建
      Option提供了动态修改Logger配置的能力,定义为接口,每个实现在闭包中修改Logger对象

      1
      2
      3
      type Option interface {
      apply(*Logger)
      }
    • 构造带固定上下文的Logger

      func (log *Logger) With(fields ...Field) *Logger

  • SugaredLogger

    • 封装了Logger,可以和Logger互相转换

      func (log *Logger) Sugar() *SugaredLogger
      func (s *SugaredLogger) Desugar() *Logger

      内部通过sweetenFields方法把(string, interface{})类型的kv参数转换为强类型的Field

      func (s *SugaredLogger) sweetenFields(args []interface{}) []Field

    • 通过With方法构造一个带固定上下文的SugaredLogger

      func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger

打印日志

  • Logger

    msg传入简单字符串,其他日志信息通过Field包装起来
    func (log *Logger) Info(msg string, fields ...Field)

    1
    logger.Info("msg", zap.String("foo", "bar"))
  • SugaredLogger

    格式化msg的方法
    func (s *SugaredLogger) Infof(template string, args ...interface{})

    1
    sugar.Infof("Failed to fetch URL: %s", url)

    带kv参数的方法
    func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{})

    1
    2
    3
    4
    5
    6
    sugar.Infow("Failed to fetch URL.",
    // Structured context as loosely typed key-value pairs.
    "url", url,
    "attempt", 3,
    "backoff", time.Second,
    )

代码

分层

zapcore 封装日志的Core接口和实现,以及level、entry、encoder、field等基础功能
zap 提供高层接口,包括sugarlogger、配置、输出接口Sink和实现、HTTP修改level接口等
其他包提供支持功能。buffer实现了一个默认size为1k的buffer池。zapgrpc封装了与grpclog兼容的日志。

阅读更多...

Go Code Style Guide

命名

包名

当命名包时,请遵守下面规则:

  • 全部小写。没有大写或下划线。
  • 简短而简洁。请记住,在每个使用的地方都完整标识了该名称。
  • 不建议使用“common”,“util”,“shared”或“lib”。这些是信息量不足的名称。

BAD

1
2
kv_log
rateLimit

GOOD

1
2
kvlog
ratelimit

函数、变量名

遵循 Go 社区关于使用 MixedCaps 作为函数名 的约定。使用单词首字母大小写命名,作用域越大的名称越详细,名字不包含下划线。
有一个例外,为了对相关的测试用例进行分组,函数名可能包含下划线,如:TestMyFunction_WhatIsBeingTested.
函数名字使用动词加名词的形式,避免使用v1/v2这类后缀.

BAD

1
2
var global_variable bool
const MAX_SIZE = 10

GOOD

1
2
var globalVariable bool
const MaxSize = 10

时间相关变量命名带上单位。

BAD

1
var expireTime int

GOOD

1
var expireMilliSeconds int
阅读更多...

LVS notes

LVS (Linux Virtual Server)

它是一种集群(Cluster)技术,采用IP负载均衡技术

主要组成部分

负载调度器(load balancer/ Director)
服务器池(server pool/ Realserver)
共享存储(shared storage)

负载均衡方式

  • Virtual Server via Network Address Translation NAT(VS/NAT)

    NAT修改请求的目的VIP和端口为选出来的后端服务器的IP和端口,发送给真实处理的服务器
    服务器处理完成,通过设置默认网关为VIP,返回结果给调度器
    调度器修改结果的源IP和端口为VIP和端口,然后返回给客户端
    in/out的流量都要经过调度器
    当集群规模变大,调度器可能成为瓶颈

  • Virtual Server via IP Tunneling(VS/TUN)

    调度器对请求的IP报文进行封装,外层为真实服务器IP
    真实服务器收到包后进行解封,获得目的地址为VIP的包,通过设置隧道设备为VIP让内核处理这个包
    处理完直接返回给客户端,因为目的地址是VIP,返回的源地址也是VIP
    调度器转发的端口和后端服务器的端口需要一致,调度器需要维护连接状态

    建立tunnel对IP报文封包转发,返回报文直接发送给用户
    需要内核支持IP-tunnel协议,性能较高

  • Virtual Server via Direct Routing(VS/DR)

修改报文Mac地址路由给real-server,真实服务器配置一个非ARP设备的IP为VIP来接收并处理请求
返回报文直接发送给用户
调度器转发的端口和后端服务器的端口需要一致,调度器需要维护连接状态
需要real-server有一块网卡和调度器连接在同一网段,性能高
对比
_ VS/NAT VS/TUN VS/DR
Server any Tunneling Non-arp device
server network private LAN/WAN LAN
server number low (10~20) High (100) High (100)
server gateway load balancer own router Own router

负载均衡调度算法

  • 最少的连接方式(Least Connection)
  • 最快模式(Fastest)
  • 观察模式(Observed)
  • 预测模式(Predictive)
  • 动态性能分配(Dynamic Ratio-APM)
  • 动态服务器补充(Dynamic Server Act.)
  • 服务质量(QoS)
  • 服务类型(ToS)
  • 规则模式

高可用

主备模式
ARP欺骗切换IP
多线路存活探测
高效状态同步

参考

http://www.linuxvirtualserver.org/zh/lvs3.html

Golang Channel小结

确保接收

1
2
3
4
5
01 go func() {
02 p := <-ch // Receive
03 }()
04
05 ch <- "paper" // Send

以上代码,当05行发送之后,不同的channel接收者的行为不同。

channel类型:

  • Buffered

    确保接收之后发送的代码才继续执行

  • Unbuffered

    发送代码继续执行,不确保此时被接收

状态和行为

状态:

  • nil
1
2
3
4
5
6
// ** nil channel
// A channel is in a nil state when it is declared to its zero value
var ch chan string

// A channel can be placed in a nil state by explicitly setting it to nil.
ch = nil
  • open
1
2
3
4
// ** open channel

// A channel is in a open state when it’s made using the built-in function make.
ch := make(chan string)
  • closed
1
2
3
4
// ** closed channel

// A channel is in a closed state when it’s closed using the built-in function close.
close(ch)

行为:

操作\状态 Nil Open Closed
Send Blocked Allowed Panic
Receive Blocked Allowed Allowed
Close Panic Allowed Panic

reference

https://www.ardanlabs.com/blog/2017/10/the-behavior-of-channels.html

  • © 2015-2024 RivenZoo
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信