go言語で作るアドサーバー2 広告を重みづけをして配信する
まず、広告がソースコードべた書きだと管理が大変なのでMySQLに広告テーブルを作ってそこからデータを読みに行くようにする。
- http://hayo0914.hatenablog.com/entry/2014/10/19/014127
- GoでMySQLに接続する - Qiita
- golangでSQLを叩くライブラリまとめ[基本/クエリビルダ/ORM] - Qiita
- Go-MySQL-Driverでunix domain socketで繋ぐ - Qiita
まず、ドライバを入れる為にgo getコマンドを使うので、まずGOPATHを設定する
gitが入っていなければgitを入れる
apt-get install git
go get github.com/go-sql-driver/mysql
mysqlのドライバを入れる
それぞれの広告の広告単価ecpmに応じて広告出現率を変更する。
ecpmの計算は、インプレッション広告だったり、クリック広告だったり、アフィリエイト(成果報酬)広告だったり、DSP(オークション)広告だったりで算出方法とシステムが異なるので、それらは予め計算されてテーブルに入っていることとする。実はここが大変だったりする。ecpmが算出されていれば、あとはそれに応じて広告の表示比率を変えるだけである。
- 広告テーブルを作る。本当はpublisherのテーブルやら、いろいろ必要だが、ここでは必要最低限のadテーブルのみとする
CREATE TABLE `ad` ( `ad_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '広告ID', `ad_type` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '広告タイプ', `ad_text` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'テキスト', `ad_ecpm` int(11) NOT NULL DEFAULT '0', `ad_create_at` datetime NOT NULL COMMENT '作成日時', `ad_update_at` datetime NOT NULL COMMENT '更新日時', `ad_delete_at` datetime DEFAULT NULL COMMENT '削除日時', `ad_delete_flg` tinyint(4) DEFAULT NULL COMMENT '削除フラグ', PRIMARY KEY (`ad_id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 COMMENT='広告テーブル'
INSERT INTO `ad`.`ad` ( `ad_id` , `ad_type` , `ad_text` , `ad_ecpm` , `ad_create_at` , `ad_update_at` , `ad_delete_at` , `ad_delete_flg` ) VALUES (NULL , '0', '[AD]広告1', '10', NOW( ) , NOW( ) , NULL , '0'), (NULL , '0', '[AD]広告2', '20', NOW( ) , NOW( ) , NULL , '0'), (NULL , '0', '[AD]広告3', '30', NOW( ) , NOW( ) , NULL , '0') ;
package main import( "fmt" "math/rand" "time" "net/http" "runtime" "database/sql" _ "github.com/go-sql-driver/mysql" ) var ( adTexts = make([]string,0) ) func handler(w http.ResponseWriter, r *http.Request) { rand.Seed(time.Now().UnixNano()) fmt.Fprintf(w,adTexts[rand.Intn(len(adTexts))]) } func main(){ // DBからデータを読み込み db, err := sql.Open("mysql", "root:@unix(/var/run/mysqld/mysqld.sock)/ad") if err != nil { panic(err.Error()) } defer db.Close() rows, err := db.Query("SELECT * FROM ad") if err != nil { panic(err.Error()) } columns, err := rows.Columns() if err != nil { panic(err.Error()) } values := make([]sql.RawBytes, len(columns)) scanArgs := make([]interface{}, len(values)) for i := range values { scanArgs[i] = &values[i] } for rows.Next() { err = rows.Scan(scanArgs...) if err != nil { panic(err.Error()) } var value string for i, col := range values { if col == nil { value = "NULL" } else { value = string(col) } if columns[i] == "ad_text" { adTexts = append(adTexts,value) } fmt.Println(columns[i], ": ", value) } fmt.Println("-----------------------------------") } runtime.GOMAXPROCS(runtime.NumCPU()) http.HandleFunc("/",handler) http.ListenAndServe(":8080",nil) }
- my.cnf tcpのポートを閉じる
[mysqld] skip-networking
go言語でSQLの処理はちょっとしんどい