A lo largo de esta charla intentaremos presentar como hemos afrontado la migración de nuestro producto multiplataforma a .NET Core, las piedras que hemos pasado en el camino, las ventajas e inconvenientes de esta aventura que hemos vivido en PlasticSCM.
3. @psluaces
@psluaces
pablo@plasticscm.com
Poco después de tener mi primer ordenador descubrí que me gustaba
más programar que jugar. Tenía 13 o 14 años y era un Amstrad PCW.
Para poder seguir programando monté una empresa en 2005.
Desarrollamos un control de versiones para competir con Perforce, IBM,
Microsoft, Subversion… y lo mejor vino luego: competir también con
Git.
Y todo lo desarrollamos en C# porque… ¿para qué complicarnos
menos?
Pablo Santos Luaces
Fundador y CTO (y también escribo posts y barro si hace falta)
11. @psluaces
¿Qué es Plastic?
Un control de versiones
muy bueno para trabajar en tareas,
muy potente con branches y merges,
que soporta grandes ficheros y grandes repos,
y muy visual
y fácil de usar (o eso intentamos).
24. @psluaces
Nos decidimos por .NET porque existía Mono
• Un control de versiones solo es serio si es multi-plataforma.
• En ningún momento nos planteamos solo-Windows.
• Existía Mono, así que nos decidimos por .NET/Mono/C#.
25. @psluaces
No fue un camino fácil
• El IDE era un dolor.
• Intentamos con otros IDEs (compramos uno X-Develop,
que no iba tampoco bien).
• Pequeñas incompatibilidades y limitaciones => hacían que
no subiéramos de framework rápidamente.
• Nos sentíamos un poco solos desarrollando “server side”.
• ¿Era realmente .NET un “system level framework”?
26. @psluaces
Llegamos a ser maintainers
de Mono en Solaris
• Tuvimos problemas con el Garbage
Collector.
• Montamos un setup para el equipo de
Mono (Mark Probst) para probar sgen.
• Hasta intentamos un port a HP-UX .
• Fixeamos bugs con big-endian :-D
27. @psluaces
Muchos de nuestros mayores servidores son
Linux
Delphi Automotive: +3000 usuarios (Global).
Pantech (2011): +1000 usuarios (Corea del Sur).
34. @psluaces
Windows Linux macOS
Viabilidad / estado actual
Server OK / OK
WinForms OK / OK
WPF OK / OK
Server OK / KO
GTKSharp OK / ??
Server OK / ??
Xam.Mac KO / KO
36. @psluaces
Qué nos interesaba de .NET Core para servidor?
• GC más estable – el mismo de .NET
• Simplificar los builds
• Idealmente: build nativo (CoreRT)
• Lateralmente: mejoras de velocidad + Pipelines
39. @psluaces
Version Control Logic
[.NET assemblies]
Network layer
[.NET assemblies]
Data Layer
[.NET assemblies]
Converts requests in
method calls
Reads and writes
data and metadata
40. @psluaces
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
41. @psluaces
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
43. @psluaces
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
44. @psluaces
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
45. @psluaces
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
Todo esto fuera
46. @psluaces
SQL Server MySQL SQLite Firebird Postgres Oracle
SQL Server
Embedded
Version Control Logic
[.NET assemblies]
Network layer
Data Layer
[.NET assemblies] Jet
.NET Remoting
[.NET assemblies]
Sockets
[.NET assemblies]
Todo esto fuera
También quitamos LDAP
Que fuera un Linux
Daemon (procesar
signals)
GitServer
Y alguna cosa más
48. @psluaces
Paso 1 -> convertirlo en un build
monolítico => 1 único “assembly”
49. @psluaces
Primer intento => diciembre 2016 (.NET Core 1)
Creamos un build en .NET Core recortando todo lo posible y eliminando funcionalidades.
Con el objetivo de probar en Linux.
Y comparar en tests de carga con Mono.
Nos llevó unas 30 horas de trabajo (durante un hack-week).
50. @psluaces
Primer intento => diciembre 2016 (.NET Core 1)
Preparar un build sin Remoting (unos cuantos cambios).
Eliminar log4net (modificado).
Eliminar ciertos cambios para un build que tenemos convirtiendo código a bytecode Java (para HP-UX! Cliente).
PlatformId no funcionaba.
Eliminar la capa de “datalayer” SQL. (Dataset, etc, etc).
ReaderWriterLock => ReaderWriterLockSlim.
Eliminar ICloneable interfaces.
Eliminar [MethodImpl(MethodImplOptions.Synchronized)].
Usamos nuestro propio PlasticBinaryReader/Writer en lugar del standard (no soportado).
53. @psluaces
Y empezamos a contactar al equipo de .NET
Core
Martin Woordward => Mono 4.6 2x faster than .NET Core 1.1 => Valentin Isac => Jose Rivero => Brian Robbins
Montamos un setup para que el equipo usase Plastic para ejecutar algún benchmark
Finalmente, en Febrero de 2017, encontraron una diferencia en cómo .NET Core implementaba
MemoryMappedView de forma diferente a .NET y Mono.
55. @psluaces
Y seguimos con pruebas
• Pequeño problema en TcpListener: https://github.com/dotnet/corefx/issues/26034
• El equipo usó Plastic para benchmark tras ver que .NET Core seguía siendo algo más lento con nuestro
workload (incluso en .NET Core 2.0)
57. @psluaces
Un control de versiones siempre tiene que
probar que es rápido
https://www.plasticscm.com/games/performance/performance-results-of-plastic-scm
Small repo (68mil ficheros y directorios, 775 MB)
Optime (sec) Plastic Git Perforce
Add 2 91 16
Checkin / Commit 15 7 118
Add + Checkin 17 98 134
5.7 times slower 8 times slower
62. @psluaces
Random crashes en uno de nuestros servidores
más importantes
Era nuestra mayor pesadilla con Mono, que algo así pudiera ocurrir.
Y comenzó a pasar.
Nuestro plan era migrar al cliente a .NET Core lo antes posible…
Tras consultar con Microsoft (Mono) y compartir core dumps => fallo en código de SGEN no fixeado en releases
posteriores a 4.6.
63. @psluaces
Pero no fue como
pensábamos
Cambiar de framework se percibía como un riesgo adicional
Y no les faltaba razón
64. @psluaces
Implementamos una solución alternativa:
watchdogs + Mono server
http://blog.plasticscm.com/2019/03/multi-instance-fault-tolerant-on-premise-server.html
Load
Balancer
WatchDog
Monitors the Plastic
server processes
Jet storage
[Container: Jet]
Storage shared by all
plasticd processes
Plastic
user
Legend
Config fileExisting systemJet
storage
New System
User
Plastic Server
process
Plastic Server
process
Plastic Server
process
65. @psluaces
Load Balancer
[nginx]
Distributes connections
among available plasticd
processes
plasticwatchdogd
[Container: .Net Core]
Starts up and monitors the
plasticd processes
Jet storage
[Container: Jet]
Storage shared by all
plasticd processes
x3
plasticd
[Container: Mono]
Each of the plastic servers
attending requests
Plastic
user
Does things Connects to Plastic
through the load
balancer (single
open external port)
Redirects connections
to the available processes
Writes to and reads from
Operating System
[Linux / Windows / macOS]
Starts up
the
watchdog
daemon on
OS startup
Starts up
nginx if
needed
plasticwatchdog.conf
[config file]
Stores configuration of the
entire setup: nodes, ports,
communication files
Reads
config
from
1. Starts up plasticd processes
2. Monitors process is still running
3. Ask process to stop periodically
or if something goes wrong
Warns watchdog
if something
is going wrong
SysAdmin
Configures
Configures and
monitors
Legend
Config fileExisting systemJet
storage
New System
User
67. @psluaces
Acierto: habíamos metido el server .NET Core en
el ciclo de build
De modo que nos aseguramos de que sigue compilando
Y comenzamos a pasar “smoke tests”
68. @psluaces
Smoke tests
+900 tests de caja negra que automatizan cliente y servidor.
Es lo que usamos cada vez que migramos a una nueva base de datos, nuevo OS (raspberry!), nuevo Mono, etc,
etc (además de pasarse en cada release).
Encontramos numerosos pequeños problemas, algunos de configuración, otros auténticos problemas por
pequeños cambios en el build (no LDAP, por ejemplo).
Los smoke son tests que automatizan la línea de comandos (usamos PNUnit para ello).
72. @psluaces
Puntos pendientes
• Linux Daemon.
• LDAP.
• Resource localization.
• Windows Service.
• Check there is enough size on disk on Linux
(MonoPosix thing that we can probably pinvoke).
• GitServer.
• WebAdmin => .NET Core, shouldn’t be a problem.
• Self Signed Certificate for SSL.
• MySQL.
• Tray.
• SQL Server.
• Name.
• NameID.
• No Tube.
• WebTriggers.
• GZipLib disabled.
• configureserver CLI not available – package multiple
exes together.
73. @psluaces
Futuro
Todos los servidores en .NET Core y release oficial en
producción
Usar ese mismo server para Plastic Cloud
Migrar Linux GUI a GTK Sharp + .NET Core => full Core
Esperar a .NET 5 para GUI Mac
Migrar Windows GUIs a .NET Core / XXX?
75. @psluaces
Conclusiones
Migrar es fácil => trabajo más bien rutinario para compilar
Es importante meterlo en el ciclo de release cuanto antes para no dejarlo abandonado
Los tests son clave (como siempre)
Es más fácil ahora con .NET Core 3.0 que hace 2 años (hay código para todo ya)
.NET Core tiene “buena prensa”. Gente horrorizada por Mono mira bien Core