Зачем и как написать свой database/sql драйвер

Зачем и как написать свой database/sql драйвер

4618c5e97c59abd315cc2d7dc809f8c8?s=128

Alexey Palazhchenko

December 07, 2018
Tweet

Transcript

  1. Зачем и как написать свой database/sql драйвер Алексей Палажченко Percona

  2. Зачем?

  3. Зачем? • Написание нового драйвера для SQL СУБД

  4. Зачем? • Написание нового драйвера для SQL СУБД • или

    исправление существующего
  5. Зачем? • Написание нового драйвера для SQL СУБД • или

    исправление существующего • Написание «наддрайвера»
  6. Зачем? • Написание нового драйвера для SQL СУБД • или

    исправление существующего • Написание «наддрайвера» • для observability и отладки
  7. Зачем? • Написание нового драйвера для SQL СУБД • или

    исправление существующего • Написание «наддрайвера» • для observability и отладки • Написание драйвера для NoSQL СУБД
  8. Зачем? • Написание нового драйвера для SQL СУБД • или

    исправление существующего • Написание «наддрайвера» • для observability и отладки • Написание драйвера для NoSQL СУБД • или даже не для СУБД
  9. Зачем? • Написание нового драйвера для SQL СУБД • https://github.com/AlekSi/mysqlx

    • Написание «наддрайвера» • https://github.com/luna-duclos/instrumentedsql • Написание драйвера для NoSQL СУБД • https://github.com/AlekSi/sqlcsv
  10. Как?

  11. Как?

  12. • func IsScanValue(v interface{}) bool • func IsValue(v interface{}) bool

    • type ColumnConverter • type Conn • type Driver • type Execer • type NotNull • func (n NotNull) ConvertValue(v interface{}) (Value, error) • type Null • func (n Null) ConvertValue(v interface{}) (Value, error) • type Result • type Rows • type RowsAffected • func (RowsAffected) LastInsertId() (int64, error) • func (v RowsAffected) RowsAffected() (int64, error) • type Stmt • type Tx • type Value • type ValueConverter • type Valuer
  13. • func IsScanValue(v interface{}) bool • func IsValue(v interface{}) bool

    • type ColumnConverter • type Conn • type ConnBeginTx • type ConnPrepareContext • type Connector • type Driver • type DriverContext • type Execer • type ExecerContext • type IsolationLevel • type NamedValue • type NamedValueChecker • type NotNull • func (n NotNull) ConvertValue(v interface{}) (Value, error) • type Null • func (n Null) ConvertValue(v interface{}) (Value, error) • type Pinger • type Queryer • type QueryerContext • type Result • type Rows • type RowsAffected • func (RowsAffected) LastInsertId() (int64, error) • func (v RowsAffected) RowsAffected() (int64, error) • type RowsColumnTypeDatabaseTypeName • type RowsColumnTypeLength • type RowsColumnTypeNullable • type RowsColumnTypePrecisionScale • type RowsColumnTypeScanType • type RowsNextResultSet • type SessionResetter • type Stmt • type StmtExecContext • type StmtQueryContext • type Tx • type TxOptions • type Value • type ValueConverter • type Valuer
  14. 3 источника знаний

  15. 3 источника знаний • Код database/sql и database/sql/driver

  16. 3 источника знаний • Код database/sql и database/sql/driver • Код

    существующих драйверов
  17. 3 источника знаний • Код database/sql и database/sql/driver • Код

    существующих драйверов • но полно плохого и старого
  18. 3 источника знаний • Код database/sql и database/sql/driver • Код

    существующих драйверов • но полно плохого и старого • Кровь, пот и падающий прод
  19. Driver // Database drivers
 // may implement DriverContext […]
 type

    Driver interface {
 Open(name string) (Conn, error)
 }
  20. Driver type driver struct{}

  21. Conn type Conn interface {
 Prepare(query string) (Stmt, error)
 Close()

    error
 
 // Deprecated: Drivers should
 // implement ConnBeginTx instead
 // (or additionally).
 Begin() (Tx, error)
 }
  22. Conn type conn struct {
 transport net.Conn
 }

  23. Stmt type Stmt interface {
 Close() error
 
 // NumInput

    may also return -1 […]
 NumInput() int
 
 // Deprecated: Drivers should implement
 // StmtExecContext instead (or additionally).
 Exec(args []Value) (Result, error)
 // Deprecated: Drivers should implement
 // StmtQueryContext instead (or additionally).
 Query(args []Value) (Rows, error)
 }
  24. Stmt type stmt struct {
 conn *conn
 query string
 }

  25. Value Value is a value that drivers must be able

    to handle. It is either nil, a type handled by a database driver's NamedValueChecker interface, or an instance of one of these types:
 int64
 float64
 bool
 []byte
 string
 time.Time type Value interface{}
  26. Result type Result interface {
 LastInsertId() (int64, error)
 RowsAffected() (int64,

    error)
 }
  27. Rows type Rows interface {
 Columns() []string
 Close() error
 Next(dest

    []Value) error
 }
  28. ErrBadConn ErrBadConn should be returned by a driver to signal

    to the sql package that a driver.Conn is in a bad state […] and the sql package should retry on a new connection. var ErrBadConn = errors.New("[…]")
  29. Rows type rows struct {
 conn *conn
 // […]
 }

  30. Минимум • driver.Open(name string) (Conn, error) • conn.Prepare(query string) (Stmt,

    error) • stmt.Exec(args []Value) (Result, error) • stmt.Query(args []Value) (Rows, error) • rows.Next(dest []Value) error
  31. QueryerContext If a Conn does not implement QueryerContext […] DB.Query

    will first prepare a query, execute the statement, and then close the statement. QueryerContext may return ErrSkip. type QueryerContext interface {
 QueryContext(context.Context, string,
 []NamedValue) (Rows, error)
 }
  32. ErrSkip ErrSkip may be returned by some optional interfaces' methods

    to indicate at runtime that the fast path is unavailable and the sql package should continue as if the optional interface was not implemented. ErrSkip is only supported where explicitly documented. var ErrSkip = errors.New("[…]")
  33. NamedValue type NamedValue struct {
 Name string
 Ordinal int
 Value

    Value
 }
  34. NamedValue type NamedValue struct {
 Name string
 Ordinal int
 Value

    interface{}
 }
  35. NamedValueChecker type NamedValueChecker interface {
 CheckNamedValue(*NamedValue) error
 }

  36. Valuer type Valuer interface {
 Value() (Value, error)
 }

  37. Valuer и Scanner type JSON []byte func (j JSON) Value()

    (driver.Value, error)
 func (j *JSON) Scan(value interface{}) error var _ driver.Valuer = JSON{}
 var _ sql.Scanner = &JSON{}
  38. Connector type Connector interface {
 Connect(context.Context) (Conn, error)
 Driver() Driver


    }
  39. Connector type Config struct {
 tlsConfig *tls.Config
 // […]
 }

    func (c *Config) Connect(ctx) (Conn, error)
  40. SessionResetter type SessionResetter interface {
 ResetSession(ctx context.Context) error
 }

  41. SessionResetter db.SetMaxIdleConns(1)
 db.SetMaxOpenConns(1)
 db.SetConnMaxLifetime(0)

  42. Наддрайверы

  43. Зачем наддрайверы?

  44. Зачем наддрайверы? • Логирование

  45. Зачем наддрайверы? • Логирование • Метрики

  46. Зачем наддрайверы? • Логирование • Метрики • Профилирование

  47. Зачем наддрайверы? • Логирование • Метрики • Профилирование • Трейсинг

  48. Зачем наддрайверы? • Логирование • Метрики • Профилирование • Трейсинг

    • Отладка
  49. Опциональные интерфейсы func (c wrappedConn) Query(query string,
 args []driver.Value)
 (driver.Rows,

    error) {
 
 queryer, ok := c.parent.(driver.Queryer)
 if ok {
 return queryer.Query(query, args)
 }
 // ???
  50. Опциональные интерфейсы func (c wrappedConn) Query(query string,
 args []driver.Value)
 (driver.Rows,

    error) {
 
 queryer, ok := c.parent.(driver.Queryer)
 if ok {
 return queryer.Query(query, args)
 }
 return nil, driver.ErrSkip
  51. Опциональные интерфейсы

  52. Опциональные интерфейсы • reflect

  53. Опциональные интерфейсы • reflect • Кодогенерация

  54. Опциональные интерфейсы • reflect • Кодогенерация • Реализация как в

    database/sql
  55. Context // Deprecated: Drivers should implement ExecerContext instead.
 type Execer

    interface {
 Exec(string, []Value) (Result, error)
 } type ExecerContext interface {
 ExecContext(ctx, string, []NamedValue)
 (Result, error)
 }
  56. Самый главный совет

  57. Тестируйте

  58. Тестируйте • На реальных системах, с минимумом моков

  59. Тестируйте • На реальных системах, с минимумом моков • На

    всех комбинациях Go и версий систем
  60. Тестируйте • На реальных системах, с минимумом моков • На

    всех комбинациях Go и версий систем • Docker Compose отлично для этого подходит
  61. Спасибо! Вопросы?

  62. Спасибо спонсорам

  63. Работа в Percona Писать Open Source за деньги https://www.percona.com
 /about-percona


    /careers
 /golang-software-engineer Go Software Engineer
 Distributed / remote
 $2500-$4000
  64. GopherCon Russia 2019 13 апреля, Москва • Приём заявок на

    доклады открыт! • Первые билеты по цене прошлого года уже в продаже! https://www.gophercon-russia.ru