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

import (
"math"
"fmt"
)

//Go语言的常量名一般不会使用全部大写或首字符大写
//在Go语言中, 首字母大写一般表示Public
//常量的数值可以作为各种类型使用


//包内常量
const car = "logo"
//批量声明常量时必须为常量赋值, 不能像变量一样只声明不赋值
const (
page = 59
book = "0 to 1"
)

func consts() {
//可以不声明类型
const filename = "x.txt"
//可以显示的声明类型, 显示声明后, 该常量的类型就已经确定
const os string = "mac os"
//不声明类型, 虽然已经赋值, 但值的类型不确定, 只是文本
const a, b = 3, 4
var c int
//由于常量a, b没有声明类型, 在使用a,b 时会自动转换为合适的数据类型
c = int(math.Sqrt(a*a + b*b))
fmt.Println(c)
}

func main() {
}

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

import (
"math"
"fmt"
)

//内建变量类型
//bool string

//u 无符号整数, 不带u为有符号整数
//(u)int (u)int8 (u)int16 (u)int32 (u)int64 uintptr
//int 为不规定长度的整形, 其长度由操作系统的位数决定
//ptr为指针

//byte rune(字符型)长度32位

//float32 float64 complex64 complex128(复数)

//Go语言中, 所有的类型转换都是显示的强制类型转换

func triangle() {
var a, b int = 3, 4
var c int
//func Sqrt(x float64) float64 接收float64类型的参数, 返回float64类型的值
//在其他语言中, int类型可以被隐式的转换为float进行计算, 但是在Go, 必须显示强制类型转换
//c 为int类型, 而函数返回值为float64类型, 所以也需要强制类型转换为int
c = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)
}

func main() {
triangle()
}

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import "fmt"

//在func外面定义的变量, 必须使用var关键字声明, 不用使用 := 的简写方式
//变量作用域为包内

//声明变量
//声明的包变量只能在函数内被赋值, 包内不允许被赋值
var a int
var b string
var c bool
var (
d int
e int
f int
)

//声明并赋值
//可以在变量后声明数据类型
var name1 int = 9
//也可以让Go自动去判断数据类型
var name2 = "ps"
var (
age int = 28
address = "China"
)
var g, h, i = 78, "uu", true


//函数内变量
func test(){
//声明
var j int
var (
k int
l string
)
//x y z 全部为bool类型
var x, y, z bool

//赋值
j = 2
k = 78
l = "BJ"

//声明并赋值
//Go编译器自动决定变量类型
var m, n = 56, "SOHO"
//r s t 全部为string类型
var r, s, t string = "hehe", "heihei", "haha"
//包内的变量声明并赋值可以使用简写方式
o, p, q := true, false, 87

fmt.Println(j, k, l, x, y, z, m, n, r, s, t, o, q, p)
}


func main() {
fmt.Println(a, b, c, d, e, f, g, h, i, name1, name2, age, address)
test()
}

该报错发生在字符串拼接时的操作, 以下字符串拼接的方式, 只要不混用, 该问题就可以解决

第一种 % 占位符

1
2
3
4
5
6
7
8
9
In [2]: s  = "abc %s" % 123

In [3]: s
Out[3]: 'abc 123'

In [4]: s = 'abc %s %s' % (123, 456)

In [5]: s
Out[5]: 'abc 123 456'

第二种 {} 大括号

1
2
3
4
5
6
7
8
9
In [6]: s = 'abc {0}'.format(123)

In [7]: s
Out[7]: 'abc 123'

In [8]: s = 'abc {0} {1}'.format(123, 456)

In [9]: s
Out[9]: 'abc 123 456'

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pymysql
from DBUtils.PooledDB import PooledDB

MYSQL_HOST = '127.0.0.1'
USER = 'zabbix'
PASSWORD = 'p@55w0rd'
DB = 'zabbix'
PORT = 3306

# 创建数据库连接池
mp = PooledDB(
pymysql, mincached=5, maxconnections=10, blocking=True,
host=MYSQL_HOST, user=USER, passwd=PASSWORD, db=DB, port=PORT, charset="utf8"
)

conn = mp.connection()
cur = conn.cursor()

sql = "select hostid from hosts where name='xxx';"
mysql.cur.execute(sql)

cur.close()
conn.close()

PooledDB的参数

  • mincached: 最少的空闲连接数, 如果空闲连接数小于这个数, pool会创建一个新的连接
  • maxcached: 最大的空闲连接数, 如果空闲连接数大于这个数, pool会关闭空闲连接
  • maxconnections: 最大的连接数
  • blocking: 当连接数达到最大的连接数时, 在请求连接的时候, 如果这个值是True, 请求连接的程序会一直等待, 直到当前连接数小于最大连接数, 如果这个值是False, 会报错

在python3代码中, 使用http.client或urllib.request进行https访问的时候, 出现以下报错

ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)

解决方法如下:

1
2
3
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

再次访问, 即可正常访问https站点

python连接mysql数据库进行查询时, 遇到以下报错: UnicodeEncodeError: 'latin-1' codec can't encode characters in position 40-41: ordinal not in range(256) 很明显提示了是字符编码的问题

发生以上问题, 是因为我在sql语句中出现了中文, 在拿到db游标对象之后, 去执行sql的时候的报错

排查数据库字符编码

登录MySQL数据库, 执行以下SQL语句执行查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)

经过查询, 发现mysql数据库本身已是 utf8 的字符编码

分析可能的原因:

mysql一般有三段配置, 分别是: [mysql] [clinet] [mysqld]

  • [mysql] 对其他远程连接的mysql客户端的配置, 例如在其他服务器执行mysql -h -u -p或使用代码进行连接
  • [client] 对本地的mysql客户端的配置, 例如在本地执行mysql -u -p
  • [mysqld] 对mysql服务进行配置

有可能mysql配置文件中的[mysql]下没有配置 default-character-set = utf8mb4, 导致远程客户端连接到服务器端后, 没有获得服务端声明的字符编码, 而使用客户端默认带的字符编码进行连接, 如果是这种情况, 可以在mysql服务端更改配置文件并重启mysql服务, 如果你不想重启数据库, 可以显示地在mysql客户端声明使用的字符编码

解决pymysql字符编码问题

1
2
3
4
5
6
7
import pymysql

db = pymysql.connect("localhost","root","123","mysql", charset="utf8")
cursor = db.cursor()

sql = "select Host, User from user where User='中文';"
cursor.execute(sql)

解决方法很简单, 只需要在创建数据库连接对象的时候, 显示地声明字符编码就可以了 charset="utf8"

注意: 如果你的MySQL服务器的字符编码使用的是utf-8 的话, 你需要声明你的连接对象的字符编码也是 utf-8

如果你的MySQL服务器的字符编码使用的是utf8mb4 的话, 相对应的, 你应该声明自己客户端的字符编码是 utf8mb4

配置heartbeat-elastic服务时日志报错如下2018-02-11T07:36:29.217-0500 ERROR pipeline/output.go:92 Failed to publish events: 400 Bad Request: {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"system_api_version [6] is not supported by system_id [beats]"}],"type":"illegal_argument_exception","reason":"system_api_version [6] is not supported by system_id [beats]"},"status":400}

解决方法:

手动设置/etc/heartbeat/heartbeat.yml 配置文件中的 name变量 name: 10.10.62.16

重启heartbeat-elastic服务即可

systemctl restart heartbeat-elastic.service

在传统的数据库中, 如果实现一个计数器的操作, 需要先去数据库中读取该值, 再程序中加1, 再讲最新的值存入数据库. 用户操作的流程步骤多不说, 还容易出现数据安全性的问题, 比如多进程/多线程的并发情况, 有可能出现A进程读取的计数器为5, 在本地执行+1, 操作的时候, 此时B进程也去执行计数器+1操作, B读取的数值也是5, 然后A将+1之后的数字6存入数据库, 之后B处理完后也将+1之后的6存入数据库, 这样就导致了在并发的情况下, 计数器的数据不准的情况.

Redis的很多操作本身都是原子性的, 例如上面案例中, 计数器+1的问题, 会有三个步骤

  • 读取数值
  • 自增操作
  • 写入数值

在传统数据库中, 为了保证数据的安全性, 这三个步骤通常是要加锁的, 也就是在步骤已经很多的情况下, 还需要考虑锁的问题. 但是Redis就不同了, Redis原子性的意思就是说, 可以保证上面的三个步骤是一个操作, 在这个操作完成之后才允许我们对其进行其他操作, 这就原生的保证了数据安全性

redis中的自增

在redis中, 如果一个key的value是数值类型, 我们就可以对这个值进行incr操作, 如果数值是整形int, 使用incr进行自增操作, 如果数值是浮点型float, 则需要使用incrbyfloat进行操作, 还有一种情况, 就是对int使用了incrbyfloat操作, 则这个数值就会变成float类型, 也就无法再对其执行incr操作了

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
38
In [1]: import redis

In [2]: pool=redis.ConnectionPool(host='127.0.0.1',port=6379,db=0)

In [3]: r = redis.StrictRedis(connection_pool=pool)

In [4]: r.keys()
Out[4]: []

In [5]: r.incr('counter')
Out[5]: 1

In [6]: r.incr('counter')
Out[6]: 2

In [7]: r.incr('counter')
Out[7]: 3

In [8]: r.incr('counter', 2)
Out[8]: 5

In [9]: r.keys()
Out[9]: [b'counter']

In [10]: r.get('counter')
Out[10]: b'5'

In [11]: r.incrbyfloat('counter')
Out[11]: 6.0

In [12]: r.incrbyfloat('counter')
Out[12]: 7.0

In [13]: r.incrbyfloat('counter', 0.1)
Out[13]: 7.1

In [14]: r.incrbyfloat('counter', 0.1)
Out[14]: 7.2

redis中的自减

redis中使用decr函数进行自减操作, 但是自减中, 没有提供类似incrbyfloat的操作, 如果在自减中想实现浮点数的效果, 可以通过在incrbyfloat函数中使用负数的方式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [19]: r.keys()
Out[19]: []

In [20]: r.incr('counter')
Out[20]: 1

In [21]: r.decr('counter')
Out[21]: 0

In [22]: r.incrbyfloat('counter', -1.1)
Out[22]: -1.1

In [23]: r.incrbyfloat('counter', -1.1)
Out[23]: -2.2

不知道这么基础的功能, 为什么Nginx官方没有提供配置~

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
#设置日志文件存放目录
logs_path="/data/logs/nginx/"
#设置pid文件
pid_path="/usr/local/openresty/nginx/logs/nginx.pid"

#重命名日志文件
mv ${logs_path}access.log ${logs_path}access_$(date -d "yesterday" +"%Y%m%d").log

#向nginx主进程发信号重新打开日志
kill -USR1 `cat ${pid_path}`

以上文件名为年月日形式, 写成脚本保存, 然后加入到计划任务里每天执行就可以了

1
2
> crontab -l
0 0 * * * /bin/bash /data/scripts/nginx_log_cut.sh >/dev/null 2>&1