西维蜀黍

【Design Pattern】Behavioural - Command

Components

Four terms always associated with the command pattern are command, receiver, invoker and client.

A command object knows about receiver and invokes a method of the receiver. Values for parameters of the receiver method are stored in the command.

The receiver then does the work when the execute() method in command is called.

An invoker object knows how to execute a command, and optionally does bookkeeping about the command execution.

The invoker does not know anything about a concrete command, it knows only about the command interface.

Invoker object(s), command objects and receiver objects are held by a client object, the client decides which receiver objects it assigns to the command objects, and which commands it assigns to the invoker. The client decides which commands to execute at which points. To execute a command, it passes the command object to the invoker object.

  ...


【Prometheus】分布式 Prometheus

联邦集群+HA

通常Prometheus高可用部署方案为联邦集群+HA的方式部署,如图所示:

在联邦+HA部署中,在每个数据中心或者VPC内以HA的方式进行Prometheus Server部署,采集当前所在数据中心或VPC内的监控目标数据,然后由一个全局的Prometheus Server负责聚合多个数据中心或VPC的监控数据,提供统一接口给用户查询,这样的部署架构看似满足高可用,但也存在诸多问题。

  1. HA双副本或者更多副本运行的Prometheus Server收集的数据如何去重?
  2. 副本故障或副滚动升级造成数据出现断点,如何将多个副本数据进行互补,保证监控数据完整性?
  3. 中心Prometheus Server既要收集全局监控数据,又要提供给用户查询。
  4. 如何把控中心Server的负载 ? b.如何将监控数据高性能的方式提供给企业内部其它团队进行查询和汇聚?
  5. 各数据中心监控数据如何长期存放?那么如何部署Prometheus,能够解决如上问题呢?
  ...


【Prometheus】Best Practice

Cardinality

Prometheus performance almost always comes down to one thing: label cardinality.

Cardinality is how many unique values of something there are. So for example a label containing HTTP methods would have a cardinality of 2 if you had only GET and POST in your application.

It’s fairly common that things start out reasonable. You might have a histogram covering 2 HTTP methods, 7 HTTP paths, 5 machines, and a Prometheus typically only monitors one environment and datacenter. So that’s 2x7x5x12 = 840. Well within the capabilities of a single Prometheus.

What tends to catch you out is that things usually don’t grow in only one dimension. Increased traffic means more machines, and more users usually means more features so new endpoints. So you might now have say 3x8x6x12, which is an increase of just 1 for each of the first three factors, resulting in 1728 or more than double the original!

It’s still small overall, but this is just one metric, from one subsystem, and this is only one minor growth spurt. Over time growth accumulates and compounds, and can bring you to a point where gradually your Prometheus starts to creak. No one change caused it, but it still needs to be dealt with before your monitoring falls over. A Prometheus 2.x can handle somewhere north of ten millions series over a time window, which is rather generous, but unwise label choices can eat that surprisingly quickly.

Scrape Interval

  ...


【Prometheus】PromQL (Prometheus Query Language)

PromQL (Prometheus Query Language)

Prometheus通过指标名称(metrics name)以及对应的一组标签(labelset)唯一定义一条时间序列。指标名称反映了监控样本的基本标识,而label则在这个基本特征上为采集到的数据提供了多种特征维度。用户可以基于这些特征维度过滤,聚合,统计从而产生新的计算后的一条时间序列。

PromQL是Prometheus内置的数据查询语言,其提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。并且被广泛应用在Prometheus的日常应用当中,包括对数据查询、可视化、告警处理当中。可以这么说,PromQL是Prometheus所有应用场景的基础,理解和掌握PromQL是Prometheus入门的第一课。

  ...


【IoT】米家设备与 Home Assistant 集成

12 Jan 2025 Update: use https://github.com/XiaoMi/ha_xiaomi_home directly as official support

ha_xiaomi_home

ref https://github.com/XiaoMi/ha_xiaomi_home

完成后,点击添加“HomeKit Bridge” 集成,按照指引完成添加。

需要注意的是,如果你希望桥接传感器类型的设备(如温湿度传感器),确保在“要包含的域”中勾选“Sensor”选项,这个选项默认是未勾选的。

Useful Tool

python-miio

$ virtualenv mymiio -p python3; cd mymiio/; source bin/activate; pip3 install python-miio

# upgrade python-miio
$ pip3 install python-miio --upgrade   -i https://pypi.python.org/simple

# 探测所有设备
$ mirobo discover --handshake 1

# 连接设备
$ miiocli device --ip 192.168.2.192 --token 8c201e5611a03347ef1f4d30e2dac6f8 info

$ miiocli --help
Usage: miiocli [OPTIONS] COMMAND [ARGS]...

Options:
  -d, --debug
  -o, --output [default|json|json_pretty]
  --version                       Show the version and exit.
  --help                          Show this message and exit.

Commands:
  ...

Reference

  ...


【IoT】Home Assistant 折腾

Config File

# 修改port
http:
  server_port: 8123
  ssl_certificate: '/etc/letsencrypt/live/your server host/fullchain.pem'
  ssl_key: '/etc/letsencrypt/live/your server host/privkey.pem
  
  
# debug
logger:
  default: debug
  ...


【Golang】类型 - Channel

Channel

Channels are type safe message queues that have the intelligence to control the behavior of any goroutine attempting to receive or send on it. A channel acts as a conduit between two goroutines and will synchronize the exchange of any resource that is passed through it. It is the channel’s ability to control the goroutines interaction that creates the synchronization mechanism.

When a channel is created with no capacity, it is called an unbuffered channel. In turn, a channel created with capacity is called a buffered channel.

熟悉Golang的人都知道一句名言:“使用通信(channel)来共享内存,而不是通过共享内存来通信”。这句话有两层意思,Go语言确实在sync包中提供了传统的锁机制,但更推荐使用channel来解决并发问题。

它的操作符是箭头 <-

ch <- v    // 发送值v到Channel ch中
v := <-ch  // 从Channel ch中接收数据,并将数据赋值给v
  ...


【Golang】使用 - 限时调用一个函数(超时退出)

使用 time.After

package main

import (
   "fmt"
   "time"
)

func main() {

   c1 := make(chan string, 1)
   go func() {
      fmt.Printf("before sleep: %v\n", time.Now())
      time.Sleep(2 * time.Second)
      c1 <- "result 1"
      // Never go to here
      fmt.Printf("after sleep: %v\n", time.Now())
   }()

   fmt.Printf("before select: %v\n", time.Now())
   select {
   case res := <-c1:
      fmt.Println(res)
   case <-time.After(1 * time.Second):
      fmt.Println("timeout 1")
   }
   fmt.Printf("after select: %v\n", time.Now())
}

Output:

before select: 2020-11-24 22:57:40.129712 +0800 +08 m=+0.000122644
before sleep: 2020-11-24 22:57:40.129721 +0800 +08 m=+0.000131671
timeout 1
after select: 2020-11-24 22:57:41.13308 +0800 +08 m=+1.003459705
  ...


【Golang】map 并发问题

Problem

If you need to read from and write to a map from concurrently executing goroutines, the accesses must be mediated by some kind of synchronization mechanism. One common way to protect maps is with sync.RWMutex.

package main
func main() {
	m := make(map[int]int)
	go func() {
		for {
			_ = m[1]
		}
	}()
	go func() {
		for {
			m[2] = 2
		}
	}()
	select {}

}

错误信息是: fatal error: concurrent map read and map write

  ...


【OpenWrt】WIFI 中继(relay)设置

This image shows an example setup. LAN interface of the Wi-Fi extender device MUST be on a different subnet for relayd to work (since it is routing traffic, it expects 2 different subnets).

Since both ethernet ports and Access Point Wi-Fi network are on the same LAN interface, all clients connecting to the Ethernet ports and to the Access Point Wi-Fi network of the Wi-Fi extender device will be routed by relayd and will be connected to your main network.

The LAN interface subnet will be used only as a “management” interface, as devices connecting to the Wi-Fi repeater will be on the main network’s subnet instead. You will have to set your PC with a static address in the same subnet as the LAN interface (like 192.168.2.10 for our example) to connect again to the Wi-Fi repeater’s Luci GUI or SSH.

  ...