MySQL to PostgreSQL migration

Install migration Ruby gem and run it:

gem install mysql2psql
mysql2psql

Update database credentials in generated mysql2psql.yml file:

mysql:
  database: redmine
  hostname: localhost
  port: 3306
  username: redmine
  password: xxxxxxx
  encoding: utf8

destination:
 # if file is given, output goes to file, else postgres
 file: /tmp/redmine-pg.sql
 postgres:
  hostname: localhost
  port: 5432
  username: mysql2psql
  password:
  database: mysql2psql_test

Run command again:

mysql2psql

Links:

Træfik on Docker Swarm mode cluster

Træfɪk is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. Since 1.1.0-rc1 it supports Docker Swarm mode as backend. It means that Træfɪk will automatically create proxying frontends which will be binded to corresponding Docker Swarm services.

This post is based on Docker Swarm (mode) cluster example.

Assuming we have Docker Swarm mode cluster already, we will need to create an overlay network:

docker network create --driver=overlay traefik-net

Backends are the simple emilevauge/whoami services:

docker service create --name test1 --label traefik.port=80 --network traefik-net emilevauge/whoami
docker service create --name test2 --label traefik.port=80 --network traefik-net emilevauge/whoami

Træfɪk itself may be ran in rich variety of configurations.

1. HTTP only proxy

docker service create \
--name traefik \
--constraint=node.role==manager \
--publish 80:80 --publish 8080:8080 \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--network traefik-net \
traefik:v1.1.0-rc3 \
--docker \
--docker.swarmmode \
--docker.domain=example.org \
--docker.watch \
--logLevel=DEBUG \
--web

Remarks:

2. HTTPS proxy with Let’s Encrypt certificate and HTTP to HTTPS redirection

docker service create \
--name traefik \
--constraint=node.role==manager \
--publish 80:80 --publish 443:443 --publish 8080:8080 \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,readonly \
--mount type=bind,source=/var/tmp,target=/etc/traefik/acme \
--network traefik-net \
traefik:v1.1.0-rc3 \
--entryPoints='Name:http Address::80 Redirect.EntryPoint:https' \
--entryPoints='Name:https Address::443 TLS' \
--defaultEntryPoints=http,https \
--acme.entryPoint=https \
--acme.email=owner@example.org \
--acme.storage=/etc/traefik/acme/acme.json \
--acme.domains=example.org \
--acme.onHostRule=true \
--docker \
--docker.swarmmode \
--docker.domain=example.org \
--docker.watch \
--web

3. HTTPS-only proxy with Let’s Encrypt certificate

docker service create \
--name traefik \
--constraint=node.role==manager \
--publish 443:443 --publish 8080:8080 \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,readonly \
--mount type=bind,source=/var/tmp,target=/etc/traefik/acme \
--network traefik-net \
traefik:v1.1.0-rc3 \
--entryPoints='Name:https Address::443 TLS' \
--defaultEntryPoints=https \
--acme.entryPoint=https \
--acme.email=owner@example.org \
--acme.storage=/etc/traefik/acme/acme.json \
--acme.domains=example.org \
--acme.onHostRule=true \
--docker \
--docker.swarmmode \
--docker.domain=example.org \
--docker.watch \
--logLevel=DEBUG \
--web

4. HTTPS-only proxy with Let’s Encrypt certificate and HTTPS web UI

docker service create \
--name traefik \
--constraint=node.role==manager \
--publish 443:443 --publish 8443:8443 \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,readonly \
--mount type=bind,source=/etc/pki/realms/domain,target=/etc/traefik/tls,readonly \
--mount type=bind,source=/var/tmp,target=/etc/traefik/acme \
--network traefik-net \
traefik:v1.1.0-rc3 \
--entryPoints='Name:https Address::443 TLS:/etc/traefik/tls/default.crt,/etc/traefik/tls/default.key' \
--defaultEntryPoints=https \
--acme.entryPoint=https \
--acme.email=owner@example.org \
--acme.storage=/etc/traefik/acme/acme.json \
--acme.domains=example.org \
--acme.onHostRule=true \
--docker \
--docker.swarmmode \
--docker.domain=example.org \
--docker.watch \
--logLevel=DEBUG \
--web.address=:8443 \
--web.certfile=/etc/traefik/tls/default.crt \
--web.keyfile=/etc/traefik/tls/default.key

5. For debugging purposes you can run Træfɪk without Docker

traefik -d \
--entryPoints='Name:http Address::8080 Redirect.EntryPoint:https' \
--entryPoints='Name:https Address::8443 TLS' \
--defaultEntryPoints=http,https \
--acme.entryPoint=https \
--acme.email=owner@example.org \
--acme.storage=acme.json \
--acme.domains=example.org
--logLevel=DEBUG \
--web

Links:

Docker registry on Centos 7

1. Create logical volumes for direct-lvm production mode

Assume that we have 40 GByte block device named as /dev/sdb with one full-size Linux partition on it.

Official Device Mapper storage driver guide recommends to use thin pools now. Use these commands to create thin-provisioned logical volumes:

pvcreate /dev/sdb1                 # Create physical volume
vgcreate docker /dev/sdb1          # Create volume group and add this physical volume to it
# Create logical volumes
lvcreate --wipesignatures y -n data docker -l 40%VG
lvcreate --wipesignatures y -n registry docker -l 40%VG
lvcreate --wipesignatures y -n metadata docker -l 2%VG
# Convert data volume to thin pool's data volume
lvconvert -y --zero n -c 512K --thinpool docker/data --poolmetadata docker/metadata
# Set thin pool autoextend features
cat > /etc/lvm/profile/docker-data.profile
activation {
        thin_pool_autoextend_threshold = 80
        thin_pool_autoextend_percent = 20
}
lvchange --metadataprofile docker-data docker/data
# Check thin pool volume (must be monitored) 
lvs -o+seg_monitor
  LV       VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor
  root     centos -wi-ao---- 117,19g
  swap     centos -wi-ao----   1,95g
  data     docker twi-a-t---  16,00g             0,00   0,01                             monitored
  registry docker -wi-a-----  16,00g

Or if you do not trust thin pools use more traditional (but deprecated in Docker) way:

pvcreate /dev/sdb1                 # Create physical volume
vgcreate docker /dev/sdb1          # Create volume group and add this physical volume to it
lvcreate -L 2G -n metadata docker  # Create logical volume for Docker metadata
lvcreate -L 15G -n data docker     # Create logical volume for Docker data (layers, containers etc)
lvcreate -L 15G -n registry docker # Create logical volume for Docker Registry data

Mount volume for Docker registry:

mkfs.xfs /dev/docker/registry
echo "/dev/docker/registry /var/lib/docker-registry    xfs     defaults        1 3" >> /etc/fstab 
mount -a

Check:

lsblk
NAME                             MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda                                8:0    0   120G  0 disk
├─sda1                             8:1    0   876M  0 part /boot
└─sda2                             8:2    0 119,1G  0 part
  ├─centos-swap                  253:0    0     2G  0 lvm  [SWAP]
  └─centos-root                  253:1    0 117,2G  0 lvm  /
sdb                                8:16   0    40G  0 disk
└─sdb1                             8:17   0    40G  0 part
  ├─docker-metadata              253:2    0     2G  0 lvm
  │ └─docker-253:1-23762136-pool 253:5    0    15G  0 dm
  ├─docker-data                  253:3    0    15G  0 lvm
  │ └─docker-253:1-23762136-pool 253:5    0    15G  0 dm
  └─docker-registry              253:4    0    15G  0 lvm  /var/lib/docker-registry

2. Configure Docker daemon

Create systemd drop-in file:

mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/env.conf 
[Service]
EnvironmentFile=-/etc/sysconfig/docker
ExecStart=
ExecStart=/usr/bin/dockerd $OPTIONS $DOCKER_NETWORK_OPTIONS $DOCKER_STORAGE_OPTIONS

Specify Docker configuration:

cat > /etc/sysconfig/docker 
OPTIONS='--iptables=false'
DOCKER_NETWORK_OPTIONS=''
DOCKER_STORAGE_OPTIONS='--storage-driver=devicemapper --storage-opt dm.datadev=/dev/docker/data --storage-opt dm.metadatadev=/dev/docker/metadata'

Check:

systemctl daemon-reload
systemctl show docker | grep EnvironmentFile
EnvironmentFile=/etc/sysconfig/docker (ignore_errors=yes)

And run:

systemctl enable docker
systemctl restart docker

Check again:

docker info | grep data
 Data file: /dev/docker/data
 Metadata file: /dev/docker/metadata
 Metadata Space Used: 639 kB
 Metadata Space Total: 2.147 GB
 Metadata Space Available: 2.147 GB

3. Obtain SSL certificate from Let’s Encrypt

It’s can be done by different ways, see Let’s Encrypt with lego and Nginx for one of these.

Assume that certificate and key was obtained and stored in /etc/pki/tls/lego/certificates directory.

4. Run Docker registry container as systemd unit

Create systemd unit:

cat > /etc/systemd/system/docker-registry.service
[Unit]
Description=Docker registry container
Requires=docker.service
After=docker.service

[Service]
Restart=always
ExecStartPre=/usr/bin/docker create -p 5000:5000 -v /var/lib/docker-registry:/var/lib/registry -v /etc/pki/tls/lego/certificates:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/example.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/example.org.key --name registry registry:2
ExecStart=/usr/bin/docker start -a registry
ExecStop=/usr/bin/docker stop -t 5 registry
ExecStopPost=/usr/bin/docker rm registry

[Install]
WantedBy=multi-user.target

5. Permit access to Docker registry only from trusted networks

firewall-cmd --zone=trusted --add-port=5000/tcp --permanent
firewall-cmd --zone=trusted --add-source=192.168.1.0/24 --permanent
firewall-cmd --reload

Since Docker daemon was launched with --iptables=false option, Docker registry port may be accessed from trusted networks only.

Links:

Let's Encrypt with lego and Nginx

xenolf/lego it’s a feature-rich Let’s Encrypt client and ACME library written in Go.

1. Prepare Nginx server

server {
    listen 80 default;
    server_name example.org www.example.org;

    location /.well-known/acme-challenge {
        proxy_pass http://127.0.0.1:81;
        proxy_set_header Host $host;
    }

    # Other directives
}

2. Update ca-certificates for CentOS 5 (optional)

Let’s Encrypt CA certificate is not included into root CA bundle of old Linux distributions like RHEL/Centos 5. You have to replace this bundle manually with fresh one from cURL website:

cp /etc/pki/tls/certs/ca-bundle.crt /etc/pki/tls/certs/ca-bundle.crt.bak
wget -O /etc/pki/tls/certs/ca-bundle.crt http://curl.haxx.se/ca/cacert.pem

3. Order the certificate from Let’s Encrypt

lego -d example.org -d www.example.org -m cert-owner@example.org -a --path=/etc/pki/tls/lego --http=:81 run

4. Update Nginx server

server {
    listen 80 default;
    server_name example.org www.example.org;

    location /.well-known/acme-challenge {
        proxy_pass http://127.0.0.1:81;
        proxy_set_header Host $host;
    }

    # Other directives
}

server {
    listen 443 ssl;
    server_name example.org www.example.org;

    ssl_certificate /etc/pki/tls/lego/certificates/example.org.crt;
    ssl_certificate_key /etc/pki/tls/lego/certificates/example.org.key;

    location /.well-known/acme-challenge {
        proxy_pass http://127.0.0.1:444;
        proxy_set_header Host $host;
    }

    # Other directives
}

5. Renew certificate every 2 month at 01:30 of first day of the month

Add to crontab:

30 01 01 */2 * /usr/local/bin/lego -d example.org -d www.example.org -m cert-owner@example.org -a --path=/etc/pki/tls/lego --http=:81 --tls=:444 renew && /usr/sbin/nginx -s reload

Links:

Выбор простого бэкапа для Windows

Доступные и функциональные системы бэкапа под Windows.

Требования:

  • Основное - использование жестких или символьных ссылок для дедупликации содержимого архива.
  • Дополнительное - использование VSS (Volume Shadow Copy Service) для предварительного создания снэпшота.

Не рассматриваются сложные распределенные (и дорогие) системы бэкапа. Один компьютер, одна программа или скрипт.

Dublicati

Duplicati is a free backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with Amazon S3, Windows Live SkyDrive, Google Drive (Google Docs), Rackspace Cloud Files or WebDAV, SSH, FTP (and many more).

Рассматривалась версия 1.3.4.

Особенности:

  • архив - zip-файл.

Преимущества:

  • бесплатность;
  • кроссплатформенность (требуются .NET 2.0+ или Mono);
  • полные и инкрементальные бэкапы;
  • есть возможность шифрования архивов;
  • используется VSS;
  • есть русский язык;
  • есть мастер восстановления.

Недостатки:

  • корявый интерфейс;
  • файловые ссылки не используются;
  • наглядность при просмотре архивов отсутствует;
  • субъективно низкая скорость работы.

Cobian Backup

Рассматривалась версия 11.

Особенности:

  • архив - каталог.

Преимущества:

  • отличный интерфейс;
  • бесплатность;
  • полные, инкрементальные и дифференциальные бэкапы;
  • есть возможность шифрования файлов в архиве (каждый файл пакуется в зашифрованный архив);
  • субъективно высокая скорость работы.
  • есть русский язык;
  • используется VSS.

Недостатки:

  • файловые ссылки не используются;
  • вообще, отличная программа, но отсутствие программы восстановления сводит все преимущества на нет - не руками же восстанавливать файлы из инкрементальных (разностных) архивов.

Рассматривалась версия 2.1.1.

Особенности:

  • архив - каталог.

Идеальная программа - подходит и под основное, и под дополнительное требования.

Преимущества:

  • отличный интерфейс;
  • используется VSS;
  • используются файловые ссылки;
  • наглядный просмотр архивов (из Проводника или программы);
  • субъективно высокая скорость работы;
  • есть возможность восстановления из программы.

Недостатки:

  • нет русского языка;
  • самый главный минус - в бесплатной версии отсутствует запуск процесса бэкапа по расписанию.
  • платная версия стоит 29 евро.

Скрипт RoboShot

Рассматривалась версия 0.3.

Особенности:

  • написан на PowerShell;
  • для копирования использует robocopy (т.е. высокая скорость работы);
  • вроде использует VSS;
  • использует файловые ссылки.

Недостатки:

  • требует доработки напильником (например, надо править регекспы с немецкой локализации Windows на русской);
  • на мой взгляд, слишком большой объем кода.

Недостатки:

  • требует доработки напильником;
  • для rsync требуется cygwin, что субъективно дает просадку по скорости.

Утилита LN и скрипт DeloreanCopy

На мой взгляд, самое простое и лучшее решение, если не нужен VSS из коробки.

DeLoreanCopy.bat требует 3 ясных параметра:

Usage: DeLoreanCopy <SourcePath> <DestPath> (<KeepMaxCopies>)
SourcePath directory containing the files to be backed up
DestPath directory where "DeLorean copy" sets will be created
KeepMaxCopies (opt.) remove any exceeding number of DLC sets before copying
e.g. DeLoreanCopy c:\data\source c:\data\backup 90

Преимущества:

  • простота;
  • бесплатность;
  • используются файловые ссылки;
  • очень просто прикручивается VSS.

Создание снэпшота с помощью vshadow и запуск скрипта vss-exec-delorean.cmd:

vshadow.exe -script=vss-setvar.cmd -exec=vss-exec-delorean.cmd c:

Скрипт vss-exec-delorean.cmd:

REM
REM called from vshadow via commandline e.g
REM
REM vshadow.exe -script=vss-setvar.cmd -exec=vss-exec.cmd e:
REM
REM vss-setvar.cmd is generated by vshadow.exe
REM
call vss-setvar.cmd
REM assign a DOS device to the created snapshot
REM
dosdev x: %shadow_device_1%
REM run the intended copy job
REM
DeLoreanCopy.bat X:\Users\paul\Documents C:\backup\ 3
REM finally remove the drive letter
REM
dosdev -r -d x:

Simple Netcat tool written in Go

It’s spectacularly simple to implement TCP Netcat in Go thanks to io.Copy.

type Progress struct {
	bytes uint64
}

func TransferStreams(con net.Conn) {
	c := make(chan Progress)

	// Read from Reader and write to Writer until EOF
	copy := func(r io.ReadCloser, w io.WriteCloser) {
		defer func() {
			r.Close()
			w.Close()
		}()
		n, _ := io.Copy(w, r)
		c <- Progress{bytes: uint64(n)}
	}

	go copy(con, os.Stdout)
	go copy(os.Stdin, con)

	p := <-c
	log.Printf("[%s]: Connection has been closed by remote peer, %d bytes has been received\n", con.RemoteAddr(), p.bytes)
	p = <-c
	log.Printf("[%s]: Local peer has been stopped, %d bytes has been sent\n", con.RemoteAddr(), p.bytes)
}

But it’s much more harder to do the same for UDP. UDP is connectionless so there is no “streams” that can be copied. You must tediously read data from connection to buffer and write this buffer to stdout by one goroutine. And read data from stdin and write it to connection from other goroutine.

Some remarks:

  • Without streams there is no EOF so we must use some predefined disconnect sequence to terminate transfer.
  • Without established connection a listener doesn’t know the remote peer address until actual data will be received. So listener must wait for data, then read this data and remote address with *net.UDPConn.ReadFrom.

const (
	// BufferLimit specifies buffer size that is sufficient to
	// handle full-size UDP datagram or TCP segment in one step
	BufferLimit = 2<<16 - 1
	// DisconnectSequence is used to disconnect UDP sessions
	DisconnectSequence = "~."
)

// Progress indicates transfer status
type Progress struct {
	remoteAddr net.Addr
	bytes      uint64
}

func TransferPackets(con net.Conn) {
	c := make(chan Progress)

	// Read from Reader and write to Writer until EOF.
	// ra is an address to whom packets must be sent in listen mode.
	copy := func(r io.ReadCloser, w io.WriteCloser, ra net.Addr) {
		defer func() {
			r.Close()
			w.Close()
		}()

		buf := make([]byte, BufferLimit)
		bytes := uint64(0)
		var n int
		var err error
		var addr net.Addr

		for {
			// Read
			if con, ok := r.(*net.UDPConn); ok {
				n, addr, err = con.ReadFrom(buf)
				// In listen mode remote address is unknown until read from
				// connection. Inform caller function with this address.
				if con.RemoteAddr() == nil && ra == nil {
					ra = addr
					c <- Progress{remoteAddr: ra}
				}
			} else {
				n, err = r.Read(buf)
			}
			if err != nil {
				if err != io.EOF {
					log.Printf("[%s]: ERROR: %s\n", ra, err)
				}
				break
			}
			if string(buf[0:n-1]) == DisconnectSequence {
				break
			}

			// Write
			if con, ok := w.(*net.UDPConn); ok && con.RemoteAddr() == nil {
				// Connection remote address must be nil otherwise
				// "WriteTo with pre-connected connection" will be thrown
				n, err = con.WriteTo(buf[0:n], ra)
			} else {
				n, err = w.Write(buf[0:n])
			}
			if err != nil {
				log.Printf("[%s]: ERROR: %s\n", ra, err)
				break
			}
			bytes += uint64(n)
		}
		c <- Progress{bytes: bytes}
	}

	ra := con.RemoteAddr()
	go copy(con, os.Stdout, ra)
	// If connection hasn't got remote address then wait for it from receiver goroutine
	if ra == nil {
		p := <-c
		ra = p.remoteAddr
		log.Printf("[%s]: Datagram has been received\n", ra)
	}
	go copy(os.Stdin, con, ra)

	p := <-c
	log.Printf("[%s]: Connection has been closed, %d bytes has been received\n", ra, p.bytes)
	p = <-c
	log.Printf("[%s]: Local peer has been stopped, %d bytes has been sent\n", ra, p.bytes)
}

Links:

Docker network and Swarm mode links

Some useful articles & videos about modern networking in Docker:

Swarm mode was presented in Docker 1.12:

Golang profiling links

Some useful articles & videos about profiling & benchmarking Go programs:

Быстрое погружение в React

Для разогрева:

После этого более-менее должно оформиться понимание, что:

  • React - это V в MVC;
  • основа React - это компоненты;
  • у компонента есть главный метод render(), который дергается React’ом, когда нужно отобразить или перерисовать компонент;
  • компоненты инициализируется через properties, и хранят state;
  • компоненты пишутся на JSX - специальный синтаксис, который “бесшовно” внедряет HTML в JS;
  • компоненты можно связывать в иерархические структуры;
  • состояние нельзя менять напрямую, а только через специальный метод setState() - таким образом React точно узнает, что состояние изменилось и объект надо перерисовать;
  • состояние принято хранить в родительском компоненте, и передавать его в дочерние компоненты через properties.

Далее надо слегка погрузиться в ECMAScript 6 aka ES2015:

Теперь рекомендую форкнуть React tutorial и поиграться с ним, например:

  • перевести проект на Webpack для дальнейшей работы с модулями, см. Setting up React for ES6 with Webpack and Babel
  • подключить live and hot reload;
  • заменить “var” на “let/const”;
  • заменить определения методов внутри объектов (Enhanced object literals);
  • заменить потенциально опасные манипуляции со сложным стейтом (объекты, массивы) с помощью Array.prototype.splice() или Array.prototype.concat() на изменения с помощью идеологически верных Immutability Helpers;
  • заменить XHR-вызовы через jQuery на что-то более REST’овое, например fetch API.

Кракая выжимка для начала работы с Webpack:

npm install --save react
npm install --save react-dom
npm install --save-dev webpack
npm install --save-dev babel-loader
npm install --save-dev babel-core
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-preset-react
npm install --save-dev react-hot-loader

Для запуска webpack-dev-server надо запустить в $HOME:

npm install webpack-dev-server

В этом случае webpack-dev-server будет установлен в $HOME/node_modules, и симлинк на него будет в $HOME/node_modules/.bin. Этот каталог уже можно включить в $PATH и запускать webpack и webpack-dev-server из любого места.

Типовое содержимое webpack.config.js:

var path = require('path');
var webpack = require('webpack');

module.exports = {
  entry: './public/scripts/example.js',
  output: {
    path: __dirname + "/public/build",
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      test: /.jsx?$/,
      loaders: ["react-hot", "babel-loader?presets[]=react,presets[]=es2015"],
      exclude: /node_modules/
    }]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(), // don't reload if there is an error
  ]
};

Теперь можно запустить webpack -w и, при любых изменениях js-файлов, будет автоматически пересобираться bundle.js. Reload в браузере все-таки придется сделать. Полноценный hot&live reload можно организовать только с помощью webpack-dev-server.


Про модули:

Про компоненты:


Внедрение fetch API:

npm install --save whatwg-fetch
npm install --save imports-loader exports-loader

Остальные ссылки по fetch:


Переходим к тяжелым упражнениям:

Чтобы не ставить nodejs, npm и bower локально, можно использовать:

Но проще всего установить nodejs & npm с https://nodejs.org.

Дополнительные компоненты:

Тестирование:

Просто интересные ресурсы:

Linearizability, serializability, transaction isolation and consistency models

Linearizability versus Serializability:

Linearizability is a guarantee about single operations on single objects. It provides a real-time (i.e., wall-clock) guarantee on the behavior of a set of single operations (often reads and writes) on a single object (e.g., distributed register or data item).

Linearizability for read and write operations is synonymous with the term “atomic consistency” and is the “C,” or “consistency,” in Gilbert and Lynch’s proof of the CAP Theorem. We say linearizability is composable (or “local”) because, if operations on each object in a system are linearizable, then all operations in the system are linearizable.

Serializability is a guarantee about transactions, or groups of one or more operations over one or more objects. It guarantees that the execution of a set of transactions (usually containing read and write operations) over multiple items is equivalent to some serial execution (total ordering) of the transactions.

Serializability is the traditional “I,” or isolation, in ACID. If users’ transactions each preserve application correctness (“C,” or consistency, in ACID), a serializable execution also preserves correctness. Therefore, serializability is a mechanism for guaranteeing database correctness.


Distributed Consistency and Session Anomalies:

In the database systems community, the gold standard is serializability. We’ve spent plenty of time looking at this in the last couple of days. Serializability concerns transactions that group multiple operations across potentially multiple objects. A serializable schedule is one that corresponds to some ordering of the transactions such that they happen one after the other in time (no concurrent / overlapping transactions). It’s the highest form of isolation between transactions.

In the distributed systems community, the gold standard is linearizability. Linearizability concerns single operations on single objects. A linearizable schedule is one where each operation appears to happen atomically at a single point in time. Once a write completes, all later reads (wall-clock time) should see the value of that write or the value of a later write. In a distributed context, we may have multiple replicas of an object’s state, and in a linearizable schedule it is as if they were all updated at once at a single point in time.

Also, small correction: the “C” in ACID is the assumption that the application program is correct (each transaction in isolation brings the database from a correct state to another correct state), whereas the AID properties are guarantees provided by the database. Together they imply serializability.


https://en.wikipedia.org/wiki/Consistency_model:

Strict consistency is the strongest consistency model. It requires that if a process reads any memory location, the value returned by the read operation is the value written by the most recent write operation to that location.

The sequential consistency model as defined by Lamport(1979) is a weaker memory model than strict consistency.

Linearizability (also known as atomic consistency) can be defined as sequential consistency with the real-time constraint.

Causal consistency can be considered a weakening model of sequential consistency by categorizing events into those causally related and those that are not. It defines that only write operations that are causally related must be seen in the same order by all processes.


A Critique of ANSI SQL Isolation Levels:


Other articles: