从MySQL client使用引出的bug聊起

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.引子 前几天一个同事在MySQL实例上执行一些数据处理,程序大致如下: modify1.go package main import ( "context" "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" "log" "time" ) func main() { db, err := sql.Open("mysql", "testdb_user:12345678@tcp(192.168.2.100:25037)/testdb?charset=utf8&loc=Asia%2FShanghai&parseTime=true") if err != nil { fmt.Println("===0===", err) } defer db.Close() tx, err := db.Begin() if err != nil { fmt.Println("===0===", err) } // 第1个SQL rows, err := tx.QueryContext(context.Background(), "select mtime, money from test where money > ?", 1) if err != nil { log.Fatal(err) } defer rows.Close() // 迭代查询结果 for rows.Next() { var mtime time.Time var money int if err := rows.Scan(&mtime, &money); err != nil { // Check for a scan error. // Query rows will be closed with defer. log.Fatal(err) } log.Println(mtime, money) // 第2个SQL result, err := tx.ExecContext(context.Background(), "insert into test2(`mtime`, `money`) values (?, ?)", mtime, money) if err != nil { log.Fatal(err) } rowsAffected, _ := result.RowsAffected() lastInsertIdresult, _ := result.LastInsertId() log.Println(rowsAffected, lastInsertIdresult) } tx.Commit() } 报错信息如下: ...

June 18, 2023 · 3 min

玩转Prometheus(5)-监控Redis和MySQL的工具包(业务层)

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引言 对于高可用的服务,监控的粒度往往都会非常细。如果恰好你也在使用 Prometheus, 也需要在业务层对Redis连接池和MySQL连接池进行监控。那么此篇文章对你而言将是一种福利。 Redis Client go-redis/redis MySQL Client jinzhu/gorm 2. 样例代码 go get github.com/vearne/golib main.go package main import ( "github.com/go-redis/redis" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/vearne/golib/metric" "log" "net/http" "time" ) func main() { // init redis client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", PoolSize: 100, }) // ***监控Redis连接池*** metric.AddRedis(client, "car") // init mysql DSN := "test:xxxx@tcp(localhost:6379)/somebiz?charset=utf8&loc=Asia%2FShanghai&parseTime=true" mysqldb, err := gorm.Open("mysql", DSN) if err != nil { panic(err) } mysqldb.DB().SetMaxIdleConns(50) mysqldb.DB().SetMaxOpenConns(100) mysqldb.DB().SetConnMaxLifetime(5 * time.Minute) // ***监控MySQL连接池*** metric.AddMySQL(mysqldb, "car") // do some thing for i := 0; i < 30; i++ { go func() { for { client.Get("a").String() time.Sleep(200 * time.Millisecond) mysqldb.Exec("show tables") } }() } http.Handle("/metrics", promhttp.Handler()) log.Fatal(http.ListenAndServe(":9090", nil)) log.Println("starting...") } func AddRedis(client RedisClient, role string) func AddMySQL(client *gorm.DB, role string) role 仅用于区分不同的Redis实例 ...

July 1, 2019 · 2 min

packetbeat 初探

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 packetbeat是elastic公司开发的网络抓包、嗅探以及分析工具。 和tcpdump一样,它的底层依赖libpcap。但它比tcpdump、tcpcopy功能强大的多。 它能够直接解析以下的网络协议 ICMP (v4 and v6) DHCP (v4) DNS HTTP AMQP 0.9.1 Cassandra Mysql PostgreSQL Redis Thrift-RPC MongoDB Memcache TLS 将网络包转换成JSON字符串,然后导出到以下output File Console Elasticsearch Logstash Kafka Redis 简单描述过程 event -> filter1 -> filter2 … -> output 让我非常吃惊的是它能够捕获MySQL、Redis等的二进制通讯协议,能够从捕获的记录中,清晰的看到每一条SQL查询语句,以及每一条Redis命令 2. 我们能拿它做什么? 据笔者的了解。 以前做线上的流量复制和重放,大致有这么几种方法 (1) 使用tcpcopy (2) 在服务中引起流量复制模块 (3) 服务打印特殊格式的日志 供后期解析,并做重放 (1)是二进制数据流,人无法阅读,(2)、(3)对服务有入侵,不够友好。 JSON格式的数据,对程序优化,对人来说阅读的障碍也不大。个人认为是个不错的选择 有了这些捕获的数据,我们可以用来做 线上排障 服务功能测试/压力测试 对请求(HTTP请求,MySQL、Redis请求等)进行统计分析,为服务优化提供必要的数据支持。 3. 安装&配置&使用 3.1 安装 见参考资料4 ...

December 17, 2018 · 2 min

基于version的MySQL并发无锁策略

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 引子: 有这么一种场景,对于外部系统提交的任务,我们要把任务扫出来,推送到 消息队列中,然后消费者监听在消息队列上, 取到任务进行消费。要防止任务被重复消费,扫出的任务要修改对应数据库状态值。 问题 假定数据库表结构为 task 字段 类型 说明 备注 id int 主键 task_id int 任务ID status int 状态 0:等待中, 1:运行中, 2:成功, 3:失败 body string 任务body体 version string 为了区分写入成功的对象 我们知道把任务扫出来,至少需要执行3步操作 扫描出等待中的任务 select * from task where status = 0 limit 10; 2)将扫出的任务推送到消息队列中 3) 修改任务状态 假定扫描出的任务task_id 分别为为1、2、3 update task set status = 1 where task_id in (1,2,3) and status = 0; 显然这个过程不是原子的,如果同时有多个scanner进行操作,显然会任务可能被重复推入消息队列中 ...

January 29, 2018 · 2 min

我在数据库方面踩过的"坑"

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 前言:前段时间在公司内部做了一个分享总结了部分我在使用各种数据库方面的遇到的问题。也在这里分享给大家。强调一下,这里的坑,我是打了引号的,有些坑,不过是某种数据库的特点,或者因为我们错误的事情而引出了问题,并不一定完全就是这种数据库有问题。 1. 业务篇 1)业务场景 不合理的业务设计,永远是对程序员最大的伤痛 在我维护的系统中有这样一种场景,用户要一次性下载全年或者半年的舆情数据,数据量会很大,单个任务就会达到数百万条数据。任何一个系统要在短时间内吞吐数据数百万条记录,也不是件很轻松的事情,尤其当这样的任务很多的时候。 目前这个时间跨度已经被调整成了3个月。说到这里不经让我想到12306错开时间发售火车票。 任何时候从业务角度的优化,总能带来立竿见影的效果 2) 字段设计 在我维护的某个系统中,同一种指标,在不同的表中,被存成了不同的字段名,这给我们带来了巨大的痛苦。所以建议对于同一种指标,或者事物使用同样的字段名(名称)进行表达、存储,否则后期光转换都要人命 3)表结构的反范式设计 大数据场景下,不要受到关系数据库范式设计的太多影响 数据机构能够立体的,尽量立体,不要扁平化 以新浪微博的一条转发举例 一条转发会包含有 这条微博的作者 这条微博的内容 text 原创微博retweeted_status 原创微博的内容 retweeted_status.text 原创微博的作者 retweeted_status.user … 一条记录就包含了这条转发,以及与这条转发相关的大部分内容,在实际使用时,无需连表查询可以方便的用NoSQL 数据库进行存储 { "created_at": "Tue May 31 17:46:55 +0800 2011", "id": 11488058246, "text": "求关注。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, "mid": "5612814510546515491", "reposts_count": 8, "comments_count": 9, "annotations": [], "user": { "id": 1404376560, "screen_name": "zaku", "name": "zaku", "province": "11", "city": "5", "location": "北京 朝阳区", "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", "url": "http://blog.sina.com.cn/zaku", "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1", "domain": "zaku", "gender": "m", "followers_count": 1204, "friends_count": 447, "statuses_count": 2908, "favourites_count": 0, "created_at": "Fri Aug 28 00:00:00 +0800 2009", "following": false, "allow_all_act_msg": false, "remark": "", "geo_enabled": true, "verified": false, "allow_all_comment": true, "avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1", "verified_reason": "", "follow_me": false, "online_status": 0, "bi_followers_count": 215 }, "retweeted_status": { "created_at": "Tue May 24 18:04:53 +0800 2011", "id": 11142488790, "text": "我的相机到了。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, "mid": "5610221544300749636", "annotations": [], "reposts_count": 5, "comments_count": 8, "user": { "id": 1073880650, "screen_name": "檀木幻想", "name": "檀木幻想", "province": "11", "city": "5", "location": "北京 朝阳区", "description": "请访问微博分析家。", "url": "http://www.weibo007.com/", "profile_image_url": "http://tp3.sinaimg.cn/1073880650/50/1285051202/1", "domain": "woodfantasy", "gender": "m", "followers_count": 723, "friends_count": 415, "statuses_count": 587, "favourites_count": 107, "created_at": "Sat Nov 14 00:00:00 +0800 2009", "following": true, "allow_all_act_msg": true, "remark": "", "geo_enabled": true, "verified": false, "allow_all_comment": true, "avatar_large": "http://tp3.sinaimg.cn/1073880650/180/1285051202/1", "verified_reason": "", "follow_me": true, "online_status": 0, "bi_followers_count": 199 } } } 2. hbase 篇 1)无法建立索引 hbase 最大的问题是无法建立索引 两个变象建立索引的办法 ...

January 1, 2018 · 3 min

kingshard初探

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因:之前的相当长时间一直在寻找mysql的分布式解决方案,一直没有特别理想的答案,有同事给推荐了kingshard,所以决定一探究竟。 1.安装 机器共3台 机器 IP 说明 机器1 192.168.122.1 安装kingshard 机器1 192.168.122.3 安装mysql实例(node1) master 没有slave 机器1 192.168.122.4 安装mysql实例(node2) master 没有slave 安装请参考官方资料 https://github.com/flike/kingshard/blob/master/doc/KingDoc/kingshard_install_document.md 我安装的kingshard 2016年8月9日的版本,目前kingshard还没有参数或配置,把kingshard以后台守护进程的方式启动,因此作者建议使用supervisor进行管理。 因为我主要是为了观察效果,所以直接在终端中启动 ./kingshard -config=../etc/ks.yaml 以下是我的配置文件 ks.yaml # server listen addr addr : 0.0.0.0:9696 # server user and password user : kingshard password : kingshard # if set log_path, the sql log will write into log_path/sql.log,the system log # will write into log_path/sys.log #log_path : /Users/flike/log # log level[debug|info|warn|error],default error log_level : debug # if set log_sql(on|off) off,the sql log will not output log_sql: on # only log the query that take more than slow_log_time ms #slow_log_time : 100 # the path of blacklist sql file # all these sqls in the file will been forbidden by kingshard #blacklist_sql_file: /Users/flike/blacklist # only allow this ip list ip to connect kingshard #allow_ips: 127.0.0.1 # the charset of kingshard, if you don't set this item # the default charset of kingshard is utf8. #proxy_charset: gbk # node is an agenda for real remote mysql server. nodes : - name : node1 # default max conns for mysql server max_conns_limit : 32 # all mysql in a node must have the same user and password user : kingshard password : kingshard # master represents a real mysql master server master : 192.168.122.3:3306 # slave represents a real mysql salve server,and the number after '@' is # read load weight of this slave. #slave : 192.168.59.101:3307@2,192.168.59.101:3307@3 down_after_noalive : 32 - name : node2 # default max conns for mysql server max_conns_limit : 32 # all mysql in a node must have the same user and password user : kingshard password : kingshard # master represents a real mysql master server master : 192.168.122.4:3306 # slave represents a real mysql salve server slave : # down mysql after N seconds noalive # 0 will no down down_after_noalive: 32 # schema defines sharding rules, the db is the sharding table database. schema : db : kingshard nodes: [node1,node2] default: node1 shard: - table: test_shard_day key: mtime # 指定分表所用的时间字段 type: date_day nodes: [node1,node2] date_range: [20160306-20160307,20160308-20160309] 由于我主要是用到kingshard的按时间分表功能,所以这里只配置了 ...

January 1, 2018 · 4 min

Percona监控工具初探

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 一直找不到合适的MySQL监控工具,正好听同事无意中说起,Percona在2016年4月发布了一个监控套件,可以同时对多个MySQL、MongoDB实例进行监控 参考资料: https://www.percona.com/blog/2016/04/18/percona-monitoring-and-management/ https://www.percona.com/doc/percona-monitoring-and-management/index.html https://www.percona.com/doc/percona-monitoring-and-management/install.html 安装过程描述的非常详尽,参考此文档足以 环境 操作系统版本CentOS 6.7 MySQL版本为 MySQL 5.7 1. 安装 1.1 PMM Server 负责将收集到的数据存储、聚合和展现 假定安装在192.168.100.1上 1) docker percona/pmm-server:1.0.6 2) docker create \ -v /opt/prometheus/data \ -v /opt/consul-data \ -v /var/lib/mysql \ -v /var/lib/grafana \ --name pmm-data \ percona/pmm-server:1.0.6 /bin/true 3) $ docker run -d \ -p 80:80 \ --volumes-from pmm-data \ --name pmm-server \ --restart always \ percona/pmm-server:1.0.6 到此,docker已经启动,可以访问 ...

January 1, 2018 · 3 min